"use client";

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

import { DataTable } from "@/components/data-table";
import { SignalLineChart } from "@/components/line-chart";
import { MetricCard } from "@/components/metric-card";
import { SectionHeading } from "@/components/section-heading";
import { StatusBadge } from "@/components/status-badge";
import {
  getPerpsDashboardLatest,
  getPerpsDashboardSeries,
  getPerpsSignalLatest,
} from "@/lib/api/client";
import { formatMetricValue, formatTimestamp } from "@/lib/format";
import { DEFAULT_INITIAL_RANGE_DAYS, RANGE_OPTIONS, rangeWindowIso, seriesMaxPoints } from "@/lib/ranges";
import type { PerpsDashboardResponse, PerpsDashboardSummary, PerpsSignalSummary } from "@/lib/api/types";
import { useStream } from "@/lib/ws/use-stream";

import { PERPS_DASHBOARDS, PERPS_SIGNAL_DESCRIPTIONS, type PerpsDashboardConfig } from "./perps-config";

export function PerpsWorkspace({
  dashboardId,
  initialLatest,
  initialSeries,
  initialSignalSummaries,
}: {
  dashboardId: string;
  initialLatest: PerpsDashboardSummary | null;
  initialSeries: PerpsDashboardResponse | null;
  initialSignalSummaries: PerpsSignalSummary[];
}) {
  const config = PERPS_DASHBOARDS.find((item) => item.id === dashboardId) ?? PERPS_DASHBOARDS[0];
  const [asset, setAsset] = useState(initialSeries?.asset ?? initialLatest?.supported_assets[0] ?? "BTC");
  const [venueScope, setVenueScope] = useState(initialSeries?.venue_scope ?? "all");
  const [rangeDays, setRangeDays] = useState(DEFAULT_INITIAL_RANGE_DAYS);
  const [quality, setQuality] = useState("all");
  const [latest, setLatest] = useState(initialLatest);
  const [series, setSeries] = useState(initialSeries);
  const [signalSummaries, setSignalSummaries] = useState(initialSignalSummaries);
  const [fetching, setFetching] = useState(false);
  const [activeTab, setActiveTab] = useState<"playbook" | "signals" | "rows">("playbook");
  const refreshAbortRef = useRef<AbortController | null>(null);
  const refreshInFlightRef = useRef(false);
  const pendingRefreshRef = useRef(false);

  useStream((event) => {
    if (event.event === "dataset.updated" || event.event === "signal.updated" || event.event === "run.updated") {
      void refresh();
    }
  });

  useEffect(() => {
    void refresh();
  }, [dashboardId, asset, venueScope, rangeDays, quality]);

  async function refresh() {
    if (refreshInFlightRef.current) {
      pendingRefreshRef.current = true;
      return;
    }
    refreshAbortRef.current?.abort();
    const controller = new AbortController();
    refreshAbortRef.current = controller;
    refreshInFlightRef.current = true;
    setFetching(true);
    try {
      const nextLatest = await getPerpsDashboardLatest(dashboardId, asset, venueScope, controller.signal);
      const { start, end } = rangeWindowIso(rangeDays, nextLatest?.latest_updated_at ?? latest?.latest_updated_at);
      const [nextSeries, ...nextSignals] = await Promise.all([
        getPerpsDashboardSeries(
          dashboardId,
          asset,
          venueScope,
          start,
          end,
          quality === "all" ? undefined : quality,
          seriesMaxPoints(rangeDays),
          controller.signal,
        ),
        ...["carry_score", "cascade_risk_score", "toxicity_score", "positioning_score", "fragility_score"].map((signalId) =>
          getPerpsSignalLatest(signalId, asset, venueScope, controller.signal),
        ),
      ]);
      if (!controller.signal.aborted) {
        setLatest(nextLatest);
        setSeries(nextSeries);
        setSignalSummaries(nextSignals.filter((item): item is PerpsSignalSummary => item !== null));
      }
    } finally {
      if (refreshAbortRef.current === controller) {
        refreshAbortRef.current = null;
      }
      refreshInFlightRef.current = false;
      setFetching(false);
      if (pendingRefreshRef.current) {
        pendingRefreshRef.current = false;
        void refresh();
      }
    }
  }

  const chartData = (series?.points ?? []).map((point) => ({ ts: point.ts, ...point.values }));
  const rows = (series?.points ?? []).slice(-12).reverse().map((point) => ({
    ts: formatTimestamp(point.ts),
    asset: point.asset ?? "—",
    venue_scope: point.venue_scope ?? "—",
    quality_flag: point.quality_flag ?? "unknown",
    ...point.values,
  }));

  return (
    <div className="pageStack">
      <SectionHeading kicker="Perps" title={`${config.title} workspace`} description={config.description} />
      <div className="twoCol">
        <div className="twoColNarrow">
          <div className="panel">
            <div className="toolbar" style={{ flexDirection: "column", alignItems: "stretch", gap: 8 }}>
              <label>
                Asset
                <select value={asset} onChange={(event) => setAsset(event.target.value)}>
                  {(latest?.supported_assets ?? ["BTC", "ETH"]).map((item) => (
                    <option key={item} value={item}>{item}</option>
                  ))}
                </select>
              </label>
              <label>
                Venue scope
                <select value={venueScope} onChange={(event) => setVenueScope(event.target.value)}>
                  {(latest?.supported_venue_scopes ?? ["all", "binance", "bybit"]).map((item) => (
                    <option key={item} value={item}>{item}</option>
                  ))}
                </select>
              </label>
              <label>
                Range
                <select value={rangeDays} onChange={(event) => setRangeDays(Number(event.target.value))}>
                  {RANGE_OPTIONS.map((days) => (
                    <option key={days} value={days}>{days}d</option>
                  ))}
                </select>
              </label>
              <label>
                Quality
                <select value={quality} onChange={(event) => setQuality(event.target.value)}>
                  <option value="all">all</option>
                  <option value="ok">ok</option>
                  <option value="partial_context">partial_context</option>
                  <option value="insufficient_history">insufficient_history</option>
                </select>
              </label>
            </div>
          </div>
          <StatusBadge label={fetching ? "LOADING" : "READY"} tone={fetching ? "neutral" : "ok"} />
          <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
            {Object.entries(latest?.latest_values ?? {}).slice(0, 4).map(([key, value]) => (
              <MetricCard
                key={key}
                label={labelize(key)}
                value={typeof value === "number" ? formatMetricValue(value, key) : String(value ?? "—")}
                tone={latest?.latest_quality === "ok" ? "ok" : "warn"}
              />
            ))}
          </div>
          <div className="panel">
            <div className="panelHeader"><h3>Companion signals</h3></div>
            <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              {config.relatedSignals.map((signalId) => (
                <Link key={signalId} href={`/perps`} style={{ color: "var(--accent)", fontSize: 12 }}>
                  {signalId.replace(/_/g, " ")}
                </Link>
              ))}
            </div>
          </div>
        </div>
        <div className="twoColWide">
          <SignalLineChart data={chartData} lines={config.lines} dualAxis={config.dualAxis} />
          <div className="tabBar">
            <button className={`tabItem ${activeTab === "playbook" ? "tabActive" : ""}`} onClick={() => setActiveTab("playbook")}>Playbook</button>
            <button className={`tabItem ${activeTab === "signals" ? "tabActive" : ""}`} onClick={() => setActiveTab("signals")}>Signals</button>
            <button className={`tabItem ${activeTab === "rows" ? "tabActive" : ""}`} onClick={() => setActiveTab("rows")}>Rows</button>
          </div>
          {activeTab === "playbook" && <PlaybookPanel config={config} />}
          {activeTab === "signals" && (
            <div className="panel">
              <ul className="summaryList">
                {signalSummaries.map((signal) => (
                  <li key={signal.id}>
                    <span>
                      <strong>{signal.name}</strong>
                      {" — "}
                      <span style={{ color: "var(--text-dim)", fontSize: 11 }}>
                        {PERPS_SIGNAL_DESCRIPTIONS[signal.id]}
                      </span>
                    </span>
                    <strong>
                      {Object.entries(signal.latest_values)
                        .map(([key, value]) => `${labelize(key)}: ${typeof value === "number" ? formatMetricValue(value, key) : value}`)
                        .join(" · ")}
                    </strong>
                  </li>
                ))}
              </ul>
            </div>
          )}
          {activeTab === "rows" && <DataTable columns={config.tableColumns} rows={rows} statusColumn="quality_flag" />}
        </div>
      </div>
    </div>
  );
}

function PlaybookPanel({ config }: { config: PerpsDashboardConfig }) {
  return (
    <div className="panel">
      <div className="panelHeader"><h3>How to use this</h3></div>
      <div className="playbookGrid">
        <PlaybookBlock title="What it measures" items={[config.playbook.whatItMeasures]} />
        <PlaybookBlock title="Interpretation" items={config.playbook.interpretation} />
        <PlaybookBlock title="Trade expressions" items={config.playbook.tradeExpressions} />
        <PlaybookBlock title="Caveats" items={config.playbook.caveats} />
        <PlaybookBlock title="Companion checks" items={config.playbook.companionChecks} />
      </div>
    </div>
  );
}

function PlaybookBlock({ title, items }: { title: string; items: string[] }) {
  return (
    <div className="playbookBlock">
      <h4>{title}</h4>
      <ul>
        {items.map((item) => <li key={item}>{item}</li>)}
      </ul>
    </div>
  );
}

function labelize(key: string) {
  return key.replace(/_/g, " ").replace(/\b\w/g, (match) => match.toUpperCase());
}
