import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { PageHeader } from '../components/ui/PageHeader';
import { Callout } from '../components/ui/Callout';
import { Disclosure } from '../components/ui/Disclosure';
import { Badge } from '../components/ui/Badge';
import { SkeletonCard, SkeletonTable } from '../components/ui/Skeleton';
import { useAuthStore } from '../stores/authStore';
import {
  getRegimeMonitor,
  getRegimeConfig,
  updateRegimeConfig,
  getRegimeFundamentals,
  updateRegimeFundamentals,
  refreshRegimeFundamentals,
} from '../api/regime';
import type {
  RegimeBand,
  RegimeMonitor,
  RegimeSignal,
  RegimeConfig,
  RegimeFundamentals,
} from '../lib/types';

const BAND_STYLES: Record<RegimeBand, { text: string; bar: string; ring: string; label: string }> = {
  stable: { text: 'text-emerald-400', bar: 'bg-emerald-400', ring: 'border-emerald-400/30', label: 'Stable' },
  watch: { text: 'text-amber-400', bar: 'bg-amber-400', ring: 'border-amber-400/30', label: 'Watch' },
  elevated: { text: 'text-orange-400', bar: 'bg-orange-400', ring: 'border-orange-400/30', label: 'Elevated' },
  breaking: { text: 'text-red-400', bar: 'bg-red-400', ring: 'border-red-400/30', label: 'Breaking' },
};

function TrendChip({ label, delta }: { label: string; delta: number | null | undefined }) {
  if (delta == null) {
    return <span className="rounded-lg bg-white/[0.04] px-2.5 py-1 text-xs text-gray-500">{label}: n/a</span>;
  }
  const rising = delta > 0;
  const flat = delta === 0;
  // Higher index = worse, so a rising score is the warning direction.
  const color = flat ? 'text-gray-400' : rising ? 'text-red-400' : 'text-emerald-400';
  const arrow = flat ? '→' : rising ? '↑' : '↓';
  return (
    <span className="rounded-lg bg-white/[0.04] px-2.5 py-1 text-xs text-gray-400">
      {label}: <span className={`font-medium ${color}`}>{arrow} {delta > 0 ? '+' : ''}{delta}</span>
    </span>
  );
}

function Gauge({ data }: { data: RegimeMonitor }) {
  const band = (data.band ?? 'stable') as RegimeBand;
  const style = BAND_STYLES[band];
  const score = data.total_score ?? 0;
  const threshold = data.alert_threshold ?? 65;
  const clamp = (v: number) => Math.min(100, Math.max(0, v));
  return (
    <div className={`glass border ${style.ring} p-6`}>
      <div className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <div className="flex items-baseline gap-3">
            <span className={`font-display text-6xl font-bold ${style.text}`}>{Math.round(score)}</span>
            <span className="text-sm text-gray-500">/ 100</span>
          </div>
          <p className={`mt-1 text-sm font-medium ${style.text}`}>{style.label}</p>
        </div>
        <div className="flex flex-wrap gap-2">
          <TrendChip label="7d" delta={data.trend?.delta_7} />
          <TrendChip label="30d" delta={data.trend?.delta_30} />
        </div>
      </div>

      {/* Band track with score + threshold markers */}
      <div className="relative mt-6 h-2 w-full rounded-full bg-gradient-to-r from-emerald-500/30 via-amber-500/30 to-red-500/40">
        <div
          className="absolute -top-1 h-4 w-0.5 -translate-x-1/2 rounded bg-gray-300/80"
          style={{ left: `${clamp(threshold)}%` }}
          title={`Alert threshold ${threshold}`}
        />
        <div
          className={`absolute -top-1.5 h-5 w-5 -translate-x-1/2 rounded-full border-2 border-white/70 ${style.bar}`}
          style={{ left: `${clamp(score)}%` }}
        />
      </div>
      <div className="mt-1.5 flex justify-between text-[10px] uppercase tracking-wider text-gray-600">
        <span>0</span><span>30</span><span>60</span><span>80</span><span>100</span>
      </div>

      <p className="mt-4 text-xs leading-relaxed text-gray-500">
        An <span className="text-gray-400">index</span> (not a calibrated probability) of how far the AI/Tech bull regime
        has deteriorated. Mostly coincident signals — it shortens reaction time, it doesn't predict the exact turn.
        {data.date && <> As of {data.date}.</>}
        {data.inputs && (data.inputs.vix != null || data.inputs.hy_oas != null) && (
          <span className="ml-1 text-gray-600">
            VIX {data.inputs.vix ?? '—'} · HY OAS {data.inputs.hy_oas ?? '—'}
          </span>
        )}
      </p>
    </div>
  );
}

function Breakdown({ breakdown }: { breakdown: RegimeSignal[] }) {
  return (
    <div className="glass overflow-hidden">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b border-white/[0.06] text-left text-xs uppercase tracking-wider text-gray-500">
            <th className="px-4 py-3 font-medium">Signal</th>
            <th className="px-4 py-3 font-medium">Sub-score</th>
            <th className="px-4 py-3 text-right font-medium">Weight</th>
            <th className="px-4 py-3 text-right font-medium">Contribution</th>
          </tr>
        </thead>
        <tbody>
          {breakdown.map((s) => (
            <tr key={s.id} className="border-b border-white/[0.03] last:border-0">
              <td className="px-4 py-3">
                <span className="font-mono text-[10px] text-gray-600">{s.id}</span>{' '}
                <span className="text-gray-300">{s.label}</span>
              </td>
              <td className="px-4 py-3">
                {s.available && s.sub_score != null ? (
                  <div className="flex items-center gap-2">
                    <div className="h-1.5 w-24 overflow-hidden rounded-full bg-white/[0.06]">
                      <div className="h-full rounded-full bg-blue-400/70" style={{ width: `${s.sub_score}%` }} />
                    </div>
                    <span className="num text-gray-300">{s.sub_score}</span>
                  </div>
                ) : (
                  <span className="text-xs text-gray-600">n/a</span>
                )}
              </td>
              <td className="px-4 py-3 text-right num text-gray-400">{s.weight}</td>
              <td className="px-4 py-3 text-right num text-gray-300">
                {s.available ? s.contribution.toFixed(1) : '—'}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function SliderRow({ label, value, onChange }: { label: string; value: number; onChange: (v: number) => void }) {
  return (
    <label className="flex items-center gap-3 text-xs text-gray-400">
      <span className="w-52 shrink-0">{label}</span>
      <input
        type="range"
        min={0}
        max={100}
        value={value}
        onChange={(e) => onChange(parseInt(e.target.value, 10))}
        className="h-2 flex-1 cursor-pointer appearance-none rounded-lg bg-gray-700 accent-blue-500"
      />
      <span className="w-8 text-right num text-gray-300">{value}</span>
    </label>
  );
}

function FundamentalsEditor({
  data,
  onSave,
  onRefresh,
  saving,
  refreshing,
}: {
  data: RegimeFundamentals;
  onSave: (body: { f1_score?: number; f3_score?: number; locked?: boolean }) => void;
  onRefresh: () => void;
  saving: boolean;
  refreshing: boolean;
}) {
  const [f1, setF1] = useState(Math.round(data.f1_score));
  const [f3, setF3] = useState(Math.round(data.f3_score));
  return (
    <div className="space-y-3">
      <div className="flex flex-wrap items-center gap-2 text-xs text-gray-500">
        <span>Source: {data.source}</span>
        {data.fetched_at && <span>· {new Date(data.fetched_at).toLocaleDateString()}</span>}
        {data.locked && <Badge label="locked" variant="manual" />}
      </div>
      {data.reasoning && <p className="text-xs leading-relaxed text-gray-400">{data.reasoning}</p>}
      <SliderRow label="F1 · Hyperscaler capex guidance" value={f1} onChange={setF1} />
      <SliderRow label="F3 · Good news, stock down" value={f3} onChange={setF3} />
      <div className="flex flex-wrap gap-2 pt-1">
        <button
          className="btn-primary px-3 py-1.5 text-sm disabled:opacity-50"
          disabled={saving}
          onClick={() => onSave({ f1_score: f1, f3_score: f3, locked: true })}
        >
          Save override
        </button>
        <button
          className="rounded-lg px-3 py-1.5 text-sm text-gray-400 hover:bg-white/[0.04] hover:text-gray-200 disabled:opacity-50"
          disabled={refreshing}
          onClick={onRefresh}
        >
          {refreshing ? 'Refreshing…' : 'Refresh via LLM'}
        </button>
        {data.locked && (
          <button
            className="rounded-lg px-3 py-1.5 text-sm text-gray-400 hover:bg-white/[0.04] hover:text-gray-200 disabled:opacity-50"
            disabled={saving}
            onClick={() => onSave({ locked: false })}
          >
            Unlock
          </button>
        )}
      </div>
    </div>
  );
}

function WeightsEditor({
  data,
  onSave,
  saving,
}: {
  data: RegimeConfig;
  onSave: (updates: Partial<RegimeConfig>) => void;
  saving: boolean;
}) {
  const [weights, setWeights] = useState<Record<string, number>>(() => ({ ...data.weights }));
  const [threshold, setThreshold] = useState<number>(data.alert_threshold);

  const setWeight = (key: string, value: string) => {
    const num = parseFloat(value);
    setWeights((prev) => ({ ...prev, [key]: isNaN(num) ? 0 : num }));
  };

  return (
    <div className="space-y-3">
      <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
        {Object.keys(weights).map((key) => (
          <label key={key} className="flex items-center justify-between gap-2 text-xs text-gray-400">
            <span className="font-mono text-gray-500">{key}</span>
            <input
              type="number"
              min={0}
              value={weights[key]}
              onChange={(e) => setWeight(key, e.target.value)}
              className="w-16 rounded-md border border-white/[0.08] bg-white/[0.03] px-2 py-1 text-right num text-gray-200"
            />
          </label>
        ))}
      </div>
      <label className="flex items-center gap-2 text-xs text-gray-400">
        <span>Alert threshold</span>
        <input
          type="number"
          min={0}
          max={100}
          value={threshold}
          onChange={(e) => setThreshold(parseInt(e.target.value, 10) || 0)}
          className="w-20 rounded-md border border-white/[0.08] bg-white/[0.03] px-2 py-1 text-right num text-gray-200"
        />
      </label>
      <button
        className="btn-primary px-3 py-1.5 text-sm disabled:opacity-50"
        disabled={saving}
        onClick={() => onSave({ weights, alert_threshold: threshold })}
      >
        Save weights
      </button>
    </div>
  );
}

function AdminControls() {
  const qc = useQueryClient();
  const fundamentals = useQuery({ queryKey: ['regime', 'fundamentals'], queryFn: getRegimeFundamentals });
  const config = useQuery({ queryKey: ['regime', 'config'], queryFn: getRegimeConfig });

  const invalidate = () => qc.invalidateQueries({ queryKey: ['regime'] });
  const refresh = useMutation({ mutationFn: refreshRegimeFundamentals, onSuccess: invalidate });
  const saveFund = useMutation({ mutationFn: updateRegimeFundamentals, onSuccess: invalidate });
  const saveConfig = useMutation({ mutationFn: updateRegimeConfig, onSuccess: invalidate });

  return (
    <div className="space-y-3">
      <Disclosure summary="Admin · Fundamentals (F1 / F3)">
        {fundamentals.isLoading && <SkeletonCard className="h-24" />}
        {fundamentals.data && (
          <FundamentalsEditor
            key={fundamentals.dataUpdatedAt}
            data={fundamentals.data}
            onSave={(body) => saveFund.mutate(body)}
            onRefresh={() => refresh.mutate()}
            saving={saveFund.isPending}
            refreshing={refresh.isPending}
          />
        )}
        {refresh.isError && (
          <Callout variant="error">Refresh failed: {(refresh.error as Error).message}</Callout>
        )}
      </Disclosure>

      <Disclosure summary="Admin · Weights & threshold">
        {config.isLoading && <SkeletonCard className="h-24" />}
        {config.data && (
          <WeightsEditor
            key={config.dataUpdatedAt}
            data={config.data}
            onSave={(updates) => saveConfig.mutate(updates)}
            saving={saveConfig.isPending}
          />
        )}
      </Disclosure>
    </div>
  );
}

export default function RegimePage() {
  const role = useAuthStore((s) => s.role);
  const isAdmin = role === 'admin';
  const monitor = useQuery({ queryKey: ['regime', 'monitor'], queryFn: getRegimeMonitor });

  return (
    <div className="space-y-6 animate-slide-up">
      <PageHeader
        title="Regime Monitor"
        subtitle="AI/Tech regime-change index — observational, feeds no trades"
      />

      {monitor.isLoading && (
        <>
          <SkeletonCard className="h-44" />
          <SkeletonTable rows={6} cols={4} />
        </>
      )}

      {monitor.isError && (
        <Callout variant="error" onRetry={() => monitor.refetch()}>
          Failed to load: {(monitor.error as Error).message}
        </Callout>
      )}

      {monitor.data && !monitor.data.available && (
        <Callout variant="empty">
          Not computed yet — run the “Regime Monitor” job from Admin → Jobs, or wait for the daily pipeline.
        </Callout>
      )}

      {monitor.data && monitor.data.available && (
        <>
          <Gauge data={monitor.data} />
          {monitor.data.breakdown && <Breakdown breakdown={monitor.data.breakdown} />}
        </>
      )}

      {isAdmin && <AdminControls />}
    </div>
  );
}
