import { useState } from 'react';
import {
  useModelPerformance,
  useModelFailures,
  useValidationSummary,
  useValidationCalibration,
  useValidationICByHorizon,
  useValidationGateStatus,
  useValidationAttributionSources,
  useValidationAttributionCatalysts,
  useValidationAttributionLayers,
} from '../api/hooks';
import type {
  ValidationSummary,
  ValidationCalibration,
  CalibrationBucket,
  ValidationICByHorizon,
  ICByHorizonEntry,
  ValidationGateStatus,
  SourceAttributionResponse,
  CatalystAttributionResponse,
  LayerAttributionResponse,
  SourceAttribution,
  CatalystAttribution,
  LayerAttribution,
} from '../api/hooks';
import { LoadingSpinner, DateRangeSelector, StatusBadge, Card } from '../components/ui';
import { AlertTriangle, ShieldCheck, ShieldX } from 'lucide-react';

type Tab = 'extraction' | 'validation';

export function OpsModelPage() {
  const [hours, setHours] = useState(24);
  const [activeTab, setActiveTab] = useState<Tab>('extraction');

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <h1 className="text-xl font-semibold text-gray-100">Model Performance</h1>
        {activeTab === 'extraction' && (
          <DateRangeSelector value={hours} onChange={setHours} />
        )}
      </div>

      {/* Tab bar */}
      <div className="flex border-b border-surface-700" role="tablist" aria-label="Model performance tabs">
        <button
          role="tab"
          aria-selected={activeTab === 'extraction'}
          onClick={() => setActiveTab('extraction')}
          className={`px-4 py-2 text-sm font-medium transition-colors ${
            activeTab === 'extraction'
              ? 'border-b-2 border-brand-500 text-brand-400'
              : 'text-gray-400 hover:text-gray-200'
          }`}
        >
          Extraction Performance
        </button>
        <button
          role="tab"
          aria-selected={activeTab === 'validation'}
          onClick={() => setActiveTab('validation')}
          className={`px-4 py-2 text-sm font-medium transition-colors ${
            activeTab === 'validation'
              ? 'border-b-2 border-brand-500 text-brand-400'
              : 'text-gray-400 hover:text-gray-200'
          }`}
        >
          Model Validation
        </button>
      </div>

      {activeTab === 'extraction' ? (
        <ExtractionTab hours={hours} />
      ) : (
        <ValidationTab />
      )}
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Extraction Performance Tab (existing content)                       */
/* ------------------------------------------------------------------ */

function ExtractionTab({ hours }: { hours: number }) {
  const { data: perf, isLoading } = useModelPerformance(hours);
  const { data: failures } = useModelFailures(hours);

  if (isLoading) return <LoadingSpinner />;

  const p = (perf ?? {}) as Record<string, unknown>;

  return (
    <div className="space-y-6">
      {/* Key metrics */}
      <div className="grid grid-cols-2 gap-3 sm:grid-cols-5">
        <StatCard label="Total Extractions" value={String(p.total_extractions ?? '—')} />
        <StatCard label="Success Rate" value={p.success_rate != null ? `${((p.success_rate as number) * 100).toFixed(1)}%` : '—'} color="text-green-400" />
        <StatCard label="Avg Latency" value={p.avg_duration_ms != null ? `${Math.round(p.avg_duration_ms as number)}ms` : '—'} />
        <StatCard label="Retry Rate" value={p.retry_rate != null ? `${((p.retry_rate as number) * 100).toFixed(1)}%` : '—'} color="text-yellow-400" />
        <StatCard label="Avg Confidence" value={p.avg_confidence != null ? ((p.avg_confidence as number) * 100).toFixed(0) + '%' : '—'} />
      </div>

      {/* Recent Failures */}
      <Card>
        <h2 className="mb-3 text-sm font-medium text-gray-400">
          Recent Failures ({(failures as unknown[])?.length ?? 0})
        </h2>
        {!(failures as unknown[])?.length ? (
          <p className="text-sm text-gray-500">No recent failures</p>
        ) : (
          <div className="space-y-2">
            {(failures as Array<Record<string, unknown>>).map((f, i) => (
              <div key={i} className="rounded border border-surface-700 bg-surface-950 p-3">
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-2">
                    <span className="font-mono text-sm text-brand-300">{String(f.ticker)}</span>
                    <StatusBadge status="failed" />
                    <span className="text-xs text-gray-500">{String(f.model_name)}</span>
                  </div>
                  <span className="text-xs text-gray-500">{f.recorded_at ? new Date(String(f.recorded_at)).toLocaleString() : ''}</span>
                </div>
                <div className="mt-1 text-xs text-gray-400">
                  {f.document_title ? String(f.document_title) : ''} ({String(f.document_type)})
                </div>
                {f.validation_errors ? (
                  <div className="mt-1 text-xs text-red-400">
                    {JSON.stringify(f.validation_errors) ?? ''}
                  </div>
                ) : null}
              </div>
            ))}
          </div>
        )}
      </Card>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Model Validation Tab (new)                                          */
/* ------------------------------------------------------------------ */

function ValidationTab() {
  const { data: summary, isLoading: summaryLoading, error: summaryError } = useValidationSummary();
  const { data: calibration, isLoading: calLoading, error: calError } = useValidationCalibration();
  const { data: icData, isLoading: icLoading, error: icError } = useValidationICByHorizon();
  const { data: gateData, isLoading: gateLoading, error: gateError } = useValidationGateStatus();
  const { data: sourcesData, isLoading: srcLoading, error: srcError } = useValidationAttributionSources();
  const { data: catalystsData, isLoading: catLoading, error: catError } = useValidationAttributionCatalysts();
  const { data: layersData, isLoading: layLoading, error: layError } = useValidationAttributionLayers();

  return (
    <div className="space-y-6">
      {/* Gate Status */}
      <GateStatusSection data={gateData} isLoading={gateLoading} error={gateError} />

      {/* Summary Cards */}
      <SummaryCardsSection data={summary} isLoading={summaryLoading} error={summaryError} />

      {/* Calibration Table */}
      <CalibrationTableSection data={calibration} isLoading={calLoading} error={calError} />

      {/* IC by Horizon Table */}
      <ICByHorizonSection data={icData} isLoading={icLoading} error={icError} />

      {/* Source Attribution Table */}
      <SourceAttributionSection data={sourcesData} isLoading={srcLoading} error={srcError} />

      {/* Catalyst Attribution Table */}
      <CatalystAttributionSection data={catalystsData} isLoading={catLoading} error={catError} />

      {/* Layer Attribution Table */}
      <LayerAttributionSection data={layersData} isLoading={layLoading} error={layError} />
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Gate Status Section                                                 */
/* ------------------------------------------------------------------ */

function GateStatusSection({ data, isLoading, error }: {
  data: ValidationGateStatus | undefined;
  isLoading: boolean;
  error: Error | null;
}) {
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorCard message="Failed to load gate status" />;

  const gate = data?.gate_status as Record<string, unknown> | null;
  if (!gate) {
    return (
      <Card className="flex items-center gap-3">
        <ShieldX size={20} className="text-yellow-400" />
        <div>
          <div className="text-sm font-medium text-yellow-400">Gate Status Unknown</div>
          <div className="text-xs text-gray-500">No gate evaluation data available</div>
        </div>
      </Card>
    );
  }

  const passed = gate.passed as boolean | undefined;
  const reason = gate.reason as string | undefined;
  const thresholds = gate.threshold_results as Array<Record<string, unknown>> | undefined;

  return (
    <Card>
      <div className="mb-3 flex items-center gap-3">
        {passed ? (
          <ShieldCheck size={20} className="text-green-400" />
        ) : (
          <ShieldX size={20} className="text-red-400" />
        )}
        <div>
          <div className={`text-sm font-medium ${passed ? 'text-green-400' : 'text-red-400'}`}>
            Live Trading Gate: {passed ? 'PASS' : 'FAIL'}
          </div>
          {reason && <div className="text-xs text-gray-500">{reason}</div>}
        </div>
      </div>

      {thresholds && thresholds.length > 0 && (
        <div className="overflow-x-auto">
          <table className="w-full text-left text-xs">
            <thead>
              <tr className="border-b border-surface-700 text-gray-500">
                <th className="pb-2 pr-4 font-medium">Threshold</th>
                <th className="pb-2 pr-4 font-medium">Required</th>
                <th className="pb-2 pr-4 font-medium">Actual</th>
                <th className="pb-2 font-medium">Status</th>
              </tr>
            </thead>
            <tbody>
              {thresholds.map((t, i) => (
                <tr key={i} className="border-b border-surface-800">
                  <td className="py-1.5 pr-4 text-gray-300">{String(t.name ?? '')}</td>
                  <td className="py-1.5 pr-4 font-mono text-gray-400">{fmtThreshold(t.threshold)}</td>
                  <td className="py-1.5 pr-4 font-mono text-gray-300">{fmtThreshold(t.actual)}</td>
                  <td className="py-1.5">
                    <StatusBadge status={t.passed ? 'success' : 'failed'} />
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </Card>
  );
}

/* ------------------------------------------------------------------ */
/* Summary Cards Section                                               */
/* ------------------------------------------------------------------ */

function SummaryCardsSection({ data, isLoading, error }: {
  data: ValidationSummary | undefined;
  isLoading: boolean;
  error: Error | null;
}) {
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorCard message="Failed to load validation summary" />;

  const snap = data?.snapshot;
  if (!snap) {
    return (
      <Card>
        <p className="text-sm text-gray-500">No validation data available yet. Metrics will appear once predictions have been evaluated.</p>
      </Card>
    );
  }

  return (
    <div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
      <StatCard label="Predictions" value={String(snap.prediction_count ?? '—')} />
      <StatCard
        label="Win Rate"
        value={fmtPct(snap.win_rate)}
        color={colorForRate(snap.win_rate, 0.53)}
      />
      <StatCard
        label="Directional Accuracy"
        value={fmtPct(snap.directional_accuracy)}
        color={colorForRate(snap.directional_accuracy, 0.53)}
      />
      <StatCard
        label="IC"
        value={fmtIC(snap.information_coefficient)}
        color={colorForIC(snap.information_coefficient)}
      />
      <StatCard
        label="Rank IC"
        value={fmtIC(snap.rank_information_coefficient)}
        color={colorForIC(snap.rank_information_coefficient)}
      />
      <StatCard
        label="Brier Score"
        value={snap.brier_score != null ? snap.brier_score.toFixed(4) : '—'}
        color={snap.brier_score != null && snap.brier_score < 0.25 ? 'text-green-400' : 'text-gray-100'}
      />
      <StatCard
        label="ECE"
        value={snap.calibration_error != null ? snap.calibration_error.toFixed(4) : '—'}
        color={snap.calibration_error != null && snap.calibration_error < 0.15 ? 'text-green-400' : 'text-yellow-400'}
      />
      <StatCard
        label="Excess vs SPY"
        value={fmtPct(snap.avg_excess_return_vs_spy)}
        color={snap.avg_excess_return_vs_spy != null && snap.avg_excess_return_vs_spy > 0 ? 'text-green-400' : 'text-red-400'}
      />
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Calibration Table Section                                           */
/* ------------------------------------------------------------------ */

function CalibrationTableSection({ data, isLoading, error }: {
  data: ValidationCalibration | undefined;
  isLoading: boolean;
  error: Error | null;
}) {
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorCard message="Failed to load calibration data" />;

  const buckets = data?.buckets;
  if (!buckets || buckets.length === 0) {
    return (
      <Card>
        <h2 className="mb-2 text-sm font-medium text-gray-400">Calibration</h2>
        <p className="text-sm text-gray-500">No calibration data available</p>
      </Card>
    );
  }

  return (
    <Card>
      <h2 className="mb-3 text-sm font-medium text-gray-400">Calibration by Confidence Bucket</h2>
      <div className="overflow-x-auto">
        <table className="w-full text-left text-xs">
          <thead>
            <tr className="border-b border-surface-700 text-gray-500">
              <th className="pb-2 pr-4 font-medium">Bucket</th>
              <th className="pb-2 pr-4 font-medium">Avg Confidence</th>
              <th className="pb-2 pr-4 font-medium">Observed Win Rate</th>
              <th className="pb-2 pr-4 font-medium">Count</th>
              <th className="pb-2 font-medium">Status</th>
            </tr>
          </thead>
          <tbody>
            {buckets.map((b: CalibrationBucket, i: number) => (
              <CalibrationRow key={i} bucket={b} />
            ))}
          </tbody>
        </table>
      </div>
    </Card>
  );
}

function CalibrationRow({ bucket }: { bucket: CalibrationBucket }) {
  const isMiscalibrated = bucket.miscalibrated ||
    Math.abs(bucket.avg_confidence - bucket.observed_win_rate) > 0.15;

  return (
    <tr className={`border-b border-surface-800 ${isMiscalibrated ? 'bg-amber-900/20' : ''}`}>
      <td className="py-1.5 pr-4 font-mono text-gray-300">
        [{fmtPctShort(bucket.bucket_low)}, {fmtPctShort(bucket.bucket_high)})
      </td>
      <td className="py-1.5 pr-4 font-mono text-gray-300">{fmtPctShort(bucket.avg_confidence)}</td>
      <td className="py-1.5 pr-4 font-mono text-gray-300">{fmtPctShort(bucket.observed_win_rate)}</td>
      <td className="py-1.5 pr-4 font-mono text-gray-400">{bucket.prediction_count}</td>
      <td className="py-1.5">
        {isMiscalibrated ? (
          <span className="inline-flex items-center gap-1 text-amber-400">
            <AlertTriangle size={14} />
            <span>Miscalibrated</span>
          </span>
        ) : (
          <span className="text-green-400">OK</span>
        )}
      </td>
    </tr>
  );
}

/* ------------------------------------------------------------------ */
/* IC by Horizon Section                                               */
/* ------------------------------------------------------------------ */

function ICByHorizonSection({ data, isLoading, error }: {
  data: ValidationICByHorizon | undefined;
  isLoading: boolean;
  error: Error | null;
}) {
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorCard message="Failed to load IC by horizon data" />;

  const horizons = data?.horizons;
  if (!horizons || horizons.length === 0) {
    return (
      <Card>
        <h2 className="mb-2 text-sm font-medium text-gray-400">IC by Horizon</h2>
        <p className="text-sm text-gray-500">No IC data available</p>
      </Card>
    );
  }

  return (
    <Card>
      <h2 className="mb-3 text-sm font-medium text-gray-400">Information Coefficient by Horizon</h2>
      <div className="overflow-x-auto">
        <table className="w-full text-left text-xs">
          <thead>
            <tr className="border-b border-surface-700 text-gray-500">
              <th className="pb-2 pr-4 font-medium">Horizon</th>
              <th className="pb-2 pr-4 font-medium">IC</th>
              <th className="pb-2 pr-4 font-medium">Rank IC</th>
              <th className="pb-2 font-medium">Predictions</th>
            </tr>
          </thead>
          <tbody>
            {horizons.map((h: ICByHorizonEntry, i: number) => (
              <tr key={i} className="border-b border-surface-800">
                <td className="py-1.5 pr-4 font-mono text-gray-300">{h.horizon}</td>
                <td className={`py-1.5 pr-4 font-mono ${colorForIC(h.information_coefficient)}`}>
                  {fmtIC(h.information_coefficient)}
                </td>
                <td className={`py-1.5 pr-4 font-mono ${colorForIC(h.rank_information_coefficient)}`}>
                  {fmtIC(h.rank_information_coefficient)}
                </td>
                <td className="py-1.5 font-mono text-gray-400">{h.prediction_count}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </Card>
  );
}

/* ------------------------------------------------------------------ */
/* Source Attribution Section                                           */
/* ------------------------------------------------------------------ */

function SourceAttributionSection({ data, isLoading, error }: {
  data: SourceAttributionResponse | undefined;
  isLoading: boolean;
  error: Error | null;
}) {
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorCard message="Failed to load source attribution data" />;

  const sources = data?.sources;
  if (!sources || sources.length === 0) {
    return (
      <Card>
        <h2 className="mb-2 text-sm font-medium text-gray-400">Source Performance</h2>
        <p className="text-sm text-gray-500">No source attribution data available</p>
      </Card>
    );
  }

  return (
    <Card>
      <h2 className="mb-3 text-sm font-medium text-gray-400">Source Performance</h2>
      <div className="overflow-x-auto">
        <table className="w-full text-left text-xs">
          <thead>
            <tr className="border-b border-surface-700 text-gray-500">
              <th className="pb-2 pr-4 font-medium">Source</th>
              <th className="pb-2 pr-4 font-medium">Win Rate</th>
              <th className="pb-2 pr-4 font-medium">IC</th>
              <th className="pb-2 pr-4 font-medium">Avg Return</th>
              <th className="pb-2 font-medium">Duplicate Rate</th>
            </tr>
          </thead>
          <tbody>
            {sources.map((s: SourceAttribution, i: number) => (
              <tr key={i} className="border-b border-surface-800">
                <td className="py-1.5 pr-4 text-gray-300">{s.source}</td>
                <td className={`py-1.5 pr-4 font-mono ${colorForRate(s.win_rate, 0.53)}`}>
                  {fmtPct(s.win_rate)}
                </td>
                <td className={`py-1.5 pr-4 font-mono ${colorForIC(s.information_coefficient)}`}>
                  {fmtIC(s.information_coefficient)}
                </td>
                <td className="py-1.5 pr-4 font-mono text-gray-300">{fmtPct(s.avg_future_return)}</td>
                <td className="py-1.5 font-mono text-gray-300">{fmtPct(s.duplicate_rate)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </Card>
  );
}

/* ------------------------------------------------------------------ */
/* Catalyst Attribution Section                                        */
/* ------------------------------------------------------------------ */

function CatalystAttributionSection({ data, isLoading, error }: {
  data: CatalystAttributionResponse | undefined;
  isLoading: boolean;
  error: Error | null;
}) {
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorCard message="Failed to load catalyst attribution data" />;

  const catalysts = data?.catalysts;
  if (!catalysts || catalysts.length === 0) {
    return (
      <Card>
        <h2 className="mb-2 text-sm font-medium text-gray-400">Catalyst Truth Table</h2>
        <p className="text-sm text-gray-500">No catalyst attribution data available</p>
      </Card>
    );
  }

  return (
    <Card>
      <h2 className="mb-3 text-sm font-medium text-gray-400">Catalyst Truth Table</h2>
      <div className="overflow-x-auto">
        <table className="w-full text-left text-xs">
          <thead>
            <tr className="border-b border-surface-700 text-gray-500">
              <th className="pb-2 pr-4 font-medium">Catalyst Type</th>
              <th className="pb-2 pr-4 font-medium">Win Rate</th>
              <th className="pb-2 pr-4 font-medium">Avg Return</th>
              <th className="pb-2 font-medium">IC</th>
            </tr>
          </thead>
          <tbody>
            {catalysts.map((c: CatalystAttribution, i: number) => (
              <tr key={i} className="border-b border-surface-800">
                <td className="py-1.5 pr-4 text-gray-300">{c.catalyst_type}</td>
                <td className={`py-1.5 pr-4 font-mono ${colorForRate(c.win_rate, 0.53)}`}>
                  {fmtPct(c.win_rate)}
                </td>
                <td className="py-1.5 pr-4 font-mono text-gray-300">{fmtPct(c.avg_future_return)}</td>
                <td className={`py-1.5 font-mono ${colorForIC(c.information_coefficient)}`}>
                  {fmtIC(c.information_coefficient)}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </Card>
  );
}

/* ------------------------------------------------------------------ */
/* Layer Attribution Section                                           */
/* ------------------------------------------------------------------ */

function LayerAttributionSection({ data, isLoading, error }: {
  data: LayerAttributionResponse | undefined;
  isLoading: boolean;
  error: Error | null;
}) {
  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorCard message="Failed to load layer attribution data" />;

  const layers = data?.layers;
  if (!layers || layers.length === 0) {
    return (
      <Card>
        <h2 className="mb-2 text-sm font-medium text-gray-400">Layer Attribution</h2>
        <p className="text-sm text-gray-500">No layer attribution data available</p>
      </Card>
    );
  }

  return (
    <Card>
      <h2 className="mb-3 text-sm font-medium text-gray-400">Layer Attribution</h2>
      <div className="overflow-x-auto">
        <table className="w-full text-left text-xs">
          <thead>
            <tr className="border-b border-surface-700 text-gray-500">
              <th className="pb-2 pr-4 font-medium">Layer</th>
              <th className="pb-2 pr-4 font-medium">Contribution %</th>
              <th className="pb-2 pr-4 font-medium">Dominant Win Rate</th>
              <th className="pb-2 font-medium">IC</th>
            </tr>
          </thead>
          <tbody>
            {layers.map((l: LayerAttribution, i: number) => (
              <tr key={i} className="border-b border-surface-800">
                <td className="py-1.5 pr-4 text-gray-300 capitalize">{l.layer}</td>
                <td className="py-1.5 pr-4 font-mono text-gray-300">{fmtPct(l.avg_contribution_pct)}</td>
                <td className={`py-1.5 pr-4 font-mono ${colorForRate(l.dominant_win_rate, 0.53)}`}>
                  {fmtPct(l.dominant_win_rate)}
                </td>
                <td className={`py-1.5 font-mono ${colorForIC(l.dominant_ic)}`}>
                  {fmtIC(l.dominant_ic)}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </Card>
  );
}

/* ------------------------------------------------------------------ */
/* Shared helpers                                                      */
/* ------------------------------------------------------------------ */

function StatCard({ label, value, color = 'text-gray-100' }: { label: string; value: string; color?: string }) {
  return (
    <Card className="text-center">
      <div className={`text-xl font-bold ${color}`}>{value}</div>
      <div className="text-xs text-gray-500">{label}</div>
    </Card>
  );
}

function ErrorCard({ message }: { message: string }) {
  return (
    <Card className="border-red-700/50 bg-red-900/20">
      <p className="text-sm text-red-400">{message}</p>
    </Card>
  );
}

/** Format a float as percentage with 1 decimal place, or '—' if null */
function fmtPct(v: number | null | undefined): string {
  if (v == null) return '—';
  return `${(v * 100).toFixed(1)}%`;
}

/** Format a float as short percentage (no decimal) for bucket display */
function fmtPctShort(v: number | null | undefined): string {
  if (v == null) return '—';
  return `${(v * 100).toFixed(0)}%`;
}

/** Format IC value with 4 decimal places, or '—' if null */
function fmtIC(v: number | null | undefined): string {
  if (v == null) return '—';
  return v.toFixed(4);
}

/** Format a threshold value for display */
function fmtThreshold(v: unknown): string {
  if (v == null) return '—';
  if (typeof v === 'number') {
    if (Number.isInteger(v)) return String(v);
    return v.toFixed(4);
  }
  return String(v);
}

/** Color for win rate / accuracy — green if above threshold, red otherwise */
function colorForRate(v: number | null | undefined, threshold: number): string {
  if (v == null) return 'text-gray-100';
  return v >= threshold ? 'text-green-400' : 'text-red-400';
}

/** Color for IC — green if positive, red if negative, gray if null */
function colorForIC(v: number | null | undefined): string {
  if (v == null) return 'text-gray-400';
  if (v >= 0.03) return 'text-green-400';
  if (v > 0) return 'text-yellow-400';
  return 'text-red-400';
}
