"use client";

import Link from "next/link";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";

import { SectionHeading } from "@/components/section-heading";
import { SignalLineChart } from "@/components/line-chart";
import { StatusBadge } from "@/components/status-badge";
import {
  getMicrostructureSignalSeries,
  getMicrostructureSignals,
  getPrices,
  getRunsSummary,
  getSignalSeries,
  getSignals,
  getSystemHealth,
} from "@/lib/api/client";
import { formatNumber, formatTimestamp } from "@/lib/format";
import type {
  MicrostructureSignalSeriesResponse,
  MicrostructureSignalSummary,
  PriceSummary,
  RunsSummary,
  SignalSeriesResponse,
  SignalSummary,
  SystemHealth,
} from "@/lib/api/types";
import { useStream } from "@/lib/ws/use-stream";

const OVERVIEW_LOOKBACK_MS = 30 * 24 * 60 * 60 * 1000;

function recentStartIso() {
  return new Date(Date.now() - OVERVIEW_LOOKBACK_MS).toISOString();
}

function microValue(values: Record<string, unknown>, key: string): number | null {
  const value = values[key];
  return typeof value === "number" ? value : null;
}

function signalKeyValues(signal: SignalSummary): { v1: string; v2: string } {
  const v = signal.latest_values;
  if (signal.family === "razor") {
    return { v1: formatNumber(v.razor_pnl), v2: formatNumber(v.razor_vrp) };
  }
  return { v1: formatNumber(v.dvol), v2: formatNumber(v.rvvix_14d) };
}

function signalChartLines(family: string | null) {
  if (family === "razor") {
    return [
      { key: "razor_pnl", label: "Razor PnL", color: "#6ac2ff" },
      { key: "razor_vrp", label: "Razor VRP", color: "#ffd166" },
      { key: "razor_pnl_zscore", label: "PnL Z", color: "#f58549" },
      { key: "razor_vrp_zscore", label: "VRP Z", color: "#8dd3c7" },
    ];
  }
  return [
    { key: "dvol", label: "DVOL", color: "#6ac2ff" },
    { key: "rvvix_14d", label: "rVVIX 14D", color: "#ffd166" },
    { key: "rvvix_30d", label: "rVVIX 30D", color: "#f58549" },
    { key: "qvvix_30d", label: "qVVIX 30D", color: "#8dd3c7" },
  ];
}

const MICRO_CHART_LINES = [
  { key: "prob_spread", label: "P(Spread)", color: "#6ac2ff" },
  { key: "expected_move_bps", label: "Expected Move", color: "#ffd166", yAxisId: "right" as const },
];

function mapSignalPoints(points: SignalSeriesResponse["points"]) {
  return points.map((p) => ({
    ts: p.ts,
    dvol: p.dvol,
    rvvix_14d: p.rvvix_14d,
    rvvix_30d: p.rvvix_30d,
    qvvix_30d: p.qvvix_30d,
    razor_pnl: p.razor_pnl,
    razor_vrp: p.razor_vrp,
    razor_pnl_zscore: p.razor_pnl_zscore,
    razor_vrp_zscore: p.razor_vrp_zscore,
  }));
}

function mapMicroPoints(points: MicrostructureSignalSeriesResponse["points"]) {
  return points.map((p) => ({
    ts: p.ts,
    prob_spread: p.prob_up != null && p.prob_down != null ? p.prob_up - p.prob_down : null,
    expected_move_bps: p.expected_move_bps,
  }));
}

type PinnedChart = {
  type: "signal";
  signal: SignalSummary;
  series: SignalSeriesResponse | null;
} | {
  type: "micro";
  signal: MicrostructureSignalSummary;
  series: MicrostructureSignalSeriesResponse | null;
};

const FAMILY_COLORS: Record<string, string> = {
  vvix: "#6ac2ff",
  razor: "#f58549",
  micro: "#ffd166",
};

export function OverviewDashboard({
  initialHealth,
  initialSignals,
  initialMicrostructureSignals,
  initialSummary,
  initialSeries,
  initialPrices,
}: {
  initialHealth: SystemHealth;
  initialSignals: SignalSummary[];
  initialMicrostructureSignals: MicrostructureSignalSummary[];
  initialSummary: RunsSummary;
  initialSeries: SignalSeriesResponse | null;
  initialPrices: PriceSummary[];
}) {
  const [health, setHealth] = useState(initialHealth);
  const [signals, setSignals] = useState(initialSignals);
  const [microstructureSignals, setMicrostructureSignals] = useState(initialMicrostructureSignals);
  const [summary, setSummary] = useState(initialSummary);
  const [prices, setPrices] = useState(initialPrices);

  // Pinned charts: keyed by signal id
  const [pinnedCharts, setPinnedCharts] = useState<Map<string, PinnedChart>>(() => {
    const m = new Map<string, PinnedChart>();
    if (initialSeries) {
      const sig = initialSignals.find((s) => s.id === initialSeries.signal_id);
      if (sig) m.set(sig.id, { type: "signal", signal: sig, series: initialSeries });
    }
    return m;
  });
  const [loadingIds, setLoadingIds] = useState<Set<string>>(new Set());
  const pinnedRef = useRef(pinnedCharts);
  pinnedRef.current = pinnedCharts;

  // Fetch signal series
  const fetchSignalSeries = useCallback(async (signalId: string, source: string) => {
    setLoadingIds((prev) => new Set(prev).add(signalId));
    const result = await getSignalSeries(signalId, source, recentStartIso(), undefined, undefined, 1000);
    if (result) {
      setPinnedCharts((prev) => {
        const next = new Map(prev);
        const existing = next.get(signalId);
        if (existing?.type === "signal") {
          next.set(signalId, { ...existing, series: result });
        }
        return next;
      });
    }
    setLoadingIds((prev) => { const n = new Set(prev); n.delete(signalId); return n; });
  }, []);

  // Fetch micro series
  const fetchMicroSeries = useCallback(async (signalId: string) => {
    setLoadingIds((prev) => new Set(prev).add(signalId));
    const result = await getMicrostructureSignalSeries(signalId, recentStartIso(), undefined, undefined, undefined, 1000);
    if (result) {
      setPinnedCharts((prev) => {
        const next = new Map(prev);
        const existing = next.get(signalId);
        if (existing?.type === "micro") {
          next.set(signalId, { ...existing, series: result });
        }
        return next;
      });
    }
    setLoadingIds((prev) => { const n = new Set(prev); n.delete(signalId); return n; });
  }, []);

  // Toggle pin for regular signal
  const toggleSignalPin = useCallback((signal: SignalSummary) => {
    setPinnedCharts((prev) => {
      const next = new Map(prev);
      if (next.has(signal.id)) {
        next.delete(signal.id);
      } else {
        next.set(signal.id, { type: "signal", signal, series: null });
        const src = signal.latest_source ?? signal.available_sources[0] ?? "dvol";
        void fetchSignalSeries(signal.id, src);
      }
      return next;
    });
  }, [fetchSignalSeries]);

  // Toggle pin for microstructure signal
  const toggleMicroPin = useCallback((signal: MicrostructureSignalSummary) => {
    setPinnedCharts((prev) => {
      const next = new Map(prev);
      if (next.has(signal.id)) {
        next.delete(signal.id);
      } else {
        next.set(signal.id, { type: "micro", signal, series: null });
        void fetchMicroSeries(signal.id);
      }
      return next;
    });
  }, [fetchMicroSeries]);

  // Unpin any chart
  const unpin = useCallback((id: string) => {
    setPinnedCharts((prev) => {
      const next = new Map(prev);
      next.delete(id);
      return next;
    });
  }, []);

  // Live updates
  useStream((event) => {
    if (event.event === "signal.updated" || event.event === "run.updated" || event.event === "dataset.updated") {
      void Promise.all([
        getSystemHealth().then(setHealth),
        getSignals().then(setSignals),
        getMicrostructureSignals().then(setMicrostructureSignals),
        getRunsSummary().then(setSummary),
        getPrices().then(setPrices),
        ...Array.from(pinnedRef.current.values()).map((pinned) => {
          if (pinned.type === "signal") {
            const source =
              pinned.signal.latest_source ?? pinned.signal.available_sources[0] ?? "dvol";
            return getSignalSeries(
              pinned.signal.id,
              source,
              recentStartIso(),
              undefined,
              undefined,
              1000,
            ).then((result) => {
              if (result) {
                setPinnedCharts((prev) => {
                  const next = new Map(prev);
                  const existing = next.get(pinned.signal.id);
                  if (existing?.type === "signal") {
                    next.set(pinned.signal.id, { ...existing, series: result });
                  }
                  return next;
                });
              }
            });
          }
          return getMicrostructureSignalSeries(
            pinned.signal.id,
            recentStartIso(),
            undefined,
            undefined,
            undefined,
            1000,
          ).then((result) => {
            if (result) {
              setPinnedCharts((prev) => {
                const next = new Map(prev);
                const existing = next.get(pinned.signal.id);
                if (existing?.type === "micro") {
                  next.set(pinned.signal.id, { ...existing, series: result });
                }
                return next;
              });
            }
          });
        }),
      ]);
    }
  });

  useEffect(() => {
    setHealth(initialHealth);
    setSignals(initialSignals);
    setMicrostructureSignals(initialMicrostructureSignals);
    setSummary(initialSummary);
  }, [initialHealth, initialSignals, initialMicrostructureSignals, initialSummary]);

  // Fetch prices client-side on mount
  useEffect(() => {
    void getPrices().then(setPrices);
  }, []);

  const pinnedList = useMemo(() => Array.from(pinnedCharts.values()), [pinnedCharts]);

  return (
    <div className="pageStack">
      {/* ── Price Ticker ── */}
      {prices.length > 0 && (
        <div className="inlineSummary" style={{ fontSize: 12 }}>
          {prices.map((p, i) => (
            <span key={p.asset}>
              {i > 0 && <span className="sep">|</span>}
              <strong>{p.asset}</strong>{" "}
              <span style={{ color: "var(--text-primary)" }}>
                {p.mid_price != null ? p.mid_price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : "—"}
              </span>{" "}
              <span style={{ color: "var(--text-dim)", fontSize: 11 }}>
                spread {p.spread_bps != null ? `${p.spread_bps}bp` : "—"}
              </span>
            </span>
          ))}
        </div>
      )}

      <SectionHeading
        kicker="Overview"
        title="Signal matrix"
        description="Click rows to pin/unpin charts. All signal families in one view."
      />

      {/* ── Unified Signal Matrix ── */}
      <div className="panel">
        <div className="panelHeader">
          <h3>All signals</h3>
          <span style={{ fontSize: 11, color: "var(--text-dim)" }}>click to pin chart</span>
        </div>
        <div className="tableWrap">
          <table className="dataTable">
            <thead>
              <tr>
                <th style={{ width: 28 }}></th>
                <th>Family</th>
                <th>Signal</th>
                <th>Key Value 1</th>
                <th>Key Value 2</th>
                <th>Quality</th>
                <th>Updated</th>
              </tr>
            </thead>
            <tbody>
              {signals.map((signal) => {
                const vals = signalKeyValues(signal);
                const isPinned = pinnedCharts.has(signal.id);
                return (
                  <tr
                    key={signal.id}
                    className={`rowClickable ${isPinned ? "rowActive" : ""}`}
                    onClick={() => toggleSignalPin(signal)}
                  >
                    <td>
                      <span style={{
                        display: "inline-block",
                        width: 8,
                        height: 8,
                        borderRadius: 2,
                        background: isPinned ? "var(--accent)" : "transparent",
                        border: isPinned ? "none" : "1px solid var(--text-dim)",
                        transition: "background 120ms",
                      }} />
                    </td>
                    <td>
                      <span style={{ color: FAMILY_COLORS[signal.family ?? ""] ?? "var(--text-dim)", fontWeight: 600, fontSize: 11, textTransform: "uppercase" }}>
                        {signal.family ?? "—"}
                      </span>
                    </td>
                    <td><strong>{signal.symbol}</strong> <span style={{ color: "var(--text-dim)", fontSize: 11 }}>{signal.name}</span></td>
                    <td>{vals.v1}</td>
                    <td>{vals.v2}</td>
                    <td>
                      <StatusBadge
                        label={signal.latest_quality ?? "unknown"}
                        tone={signal.latest_quality === "ok" ? "ok" : "warn"}
                      />
                    </td>
                    <td>{formatTimestamp(signal.latest_updated_at)}</td>
                  </tr>
                );
              })}
              {microstructureSignals.map((signal) => {
                const isPinned = pinnedCharts.has(signal.id);
                return (
                  <tr
                    key={signal.id}
                    className={`rowClickable ${isPinned ? "rowActive" : ""}`}
                    onClick={() => toggleMicroPin(signal)}
                  >
                    <td>
                      <span style={{
                        display: "inline-block",
                        width: 8,
                        height: 8,
                        borderRadius: 2,
                        background: isPinned ? "var(--accent)" : "transparent",
                        border: isPinned ? "none" : "1px solid var(--text-dim)",
                        transition: "background 120ms",
                      }} />
                    </td>
                    <td>
                      <span style={{ color: FAMILY_COLORS.micro, fontWeight: 600, fontSize: 11, textTransform: "uppercase" }}>
                        micro
                      </span>
                    </td>
                    <td>
                      <Link
                        href={`/microstructure/predictions?asset=${signal.asset}&horizon=${signal.horizon}`}
                        style={{ color: "var(--accent)" }}
                        onClick={(e) => e.stopPropagation()}
                      >
                        {signal.name}
                      </Link>
                    </td>
                    <td>{formatNumber(microValue(signal.latest_values, "prob_up"))}</td>
                    <td>{formatNumber(microValue(signal.latest_values, "expected_move_bps"))}</td>
                    <td>
                      <StatusBadge
                        label={signal.latest_quality ?? "unknown"}
                        tone={signal.latest_quality === "ok" ? "ok" : "warn"}
                      />
                    </td>
                    <td>{formatTimestamp(signal.latest_updated_at)}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>

      {/* ── Pinned Charts ── */}
      {pinnedList.length > 0 && (
        <div className="chartGrid">
          {pinnedList.map((pinned) => {
            const id = pinned.type === "signal" ? pinned.signal.id : pinned.signal.id;
            const isLoading = loadingIds.has(id);
            const label = pinned.type === "signal" ? pinned.signal.symbol : pinned.signal.name;
            const sublabel = pinned.type === "signal" ? pinned.signal.name : `${pinned.signal.asset} ${pinned.signal.horizon}`;

            let chartData: Record<string, string | number | null>[];
            let chartLines: { key: string; label: string; color: string; yAxisId?: string }[];
            let refLines: { y: number; label?: string }[] | undefined;

            if (pinned.type === "signal") {
              chartData = mapSignalPoints(pinned.series?.points ?? []);
              chartLines = signalChartLines(pinned.signal.family);
              refLines = pinned.signal.family === "razor" ? [{ y: 0, label: "zero" }] : undefined;
            } else {
              chartData = mapMicroPoints(pinned.series?.points ?? []);
              chartLines = MICRO_CHART_LINES;
              refLines = [{ y: 0, label: "zero" }];
            }

            return (
              <div key={id} className="panel">
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 8 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                    <h3 style={{ margin: 0, fontSize: "0.82rem", fontWeight: 600 }}>{label}</h3>
                    <span style={{ fontSize: 11, color: "var(--text-dim)" }}>{sublabel}</span>
                    {isLoading && <span className="fetchingIndicator">loading</span>}
                  </div>
                  <button
                    onClick={() => unpin(id)}
                    style={{
                      background: "none",
                      border: "1px solid var(--border)",
                      borderRadius: 3,
                      color: "var(--text-dim)",
                      cursor: "pointer",
                      padding: "3px 8px",
                      fontSize: 11,
                      fontFamily: "var(--font-mono)",
                    }}
                    title="Unpin chart"
                  >
                    ✕
                  </button>
                </div>
                <SignalLineChart
                  data={chartData}
                  lines={chartLines}
                  referenceLines={refLines}
                  dualAxis
                  height={pinnedList.length > 2 ? 280 : 380}
                  loading={isLoading}
                />
              </div>
            );
          })}
        </div>
      )}

      {pinnedList.length === 0 && (
        <div className="panel" style={{ textAlign: "center", padding: "24px 12px" }}>
          <p style={{ color: "var(--text-dim)", fontSize: 12, margin: 0 }}>
            Click signals above to pin charts here
          </p>
        </div>
      )}

      {/* ── Health bar ── */}
      <div className="inlineSummary">
        <strong>{health.status}</strong>
        <span className="sep">|</span>
        <strong style={{ color: "var(--ok)" }}>{summary.success_count}</strong>/{summary.total_runs} runs
        <span className="sep">|</span>
        <strong style={{ color: "var(--warn)" }}>{summary.gap_count}</strong> gaps
        <span className="sep">|</span>
        <strong style={{ color: "var(--danger)" }}>{summary.failed_count}</strong> failed
        <span className="sep">|</span>
        {health.dataset_count} datasets
        <span className="sep">|</span>
        last signal {formatTimestamp(health.latest_signal_update)}
      </div>
    </div>
  );
}
