"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 {
  getOptionsDashboardLatest,
  getOptionsDashboardSeries,
  getOptionsSignalLatest,
} from "@/lib/api/client";
import { formatMetricValue, formatTimestamp } from "@/lib/format";
import { DEFAULT_INITIAL_RANGE_DAYS, RANGE_OPTIONS, rangeWindowIso, seriesMaxPoints } from "@/lib/ranges";
import type {
  OptionsDashboardResponse,
  OptionsDashboardSummary,
  OptionsSignalSummary,
} from "@/lib/api/types";
import { useStream } from "@/lib/ws/use-stream";

import {
  OPTIONS_DASHBOARDS,
  OPTIONS_SIGNAL_DESCRIPTIONS,
  type OptionsDashboardConfig,
} from "./options-config";

export function OptionsWorkspace({
  dashboardId,
  initialLatest,
  initialSeries,
  initialSignalSummaries,
}: {
  dashboardId: string;
  initialLatest: OptionsDashboardSummary | null;
  initialSeries: OptionsDashboardResponse | null;
  initialSignalSummaries: OptionsSignalSummary[];
}) {
  const config = OPTIONS_DASHBOARDS.find((item) => item.id === dashboardId) ?? OPTIONS_DASHBOARDS[0];
  const [underlying, setUnderlying] = useState(
    initialSeries?.underlying ?? initialLatest?.supported_underlyings[0] ?? "BTC",
  );
  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, underlying, 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 getOptionsDashboardLatest(
        dashboardId,
        supportsUnderlying(config) ? underlying : undefined,
        controller.signal,
      );
      const { start, end } = rangeWindowIso(rangeDays, nextLatest?.latest_updated_at ?? latest?.latest_updated_at);
      const [nextSeries, ...nextSignals] = await Promise.all([
        getOptionsDashboardSeries(
          dashboardId,
          supportsUnderlying(config) ? underlying : undefined,
          start,
          end,
          quality === "all" ? undefined : quality,
          seriesMaxPoints(rangeDays),
          controller.signal,
        ),
        ...[
          ...Object.keys(OPTIONS_SIGNAL_DESCRIPTIONS),
        ].map((signalId) => getOptionsSignalLatest(signalId, underlying, controller.signal)),
      ]);
      if (!controller.signal.aborted) {
        setLatest(nextLatest);
        setSeries(nextSeries);
        setSignalSummaries(nextSignals.filter((item): item is OptionsSignalSummary => 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),
    tenor: point.tenor ?? "—",
    tenor_bucket: point.tenor_bucket ?? "—",
    moneyness_bucket: point.moneyness_bucket ?? "—",
    expiry_bucket: point.expiry_bucket ?? "—",
    strike_bucket: point.strike_bucket ?? "—",
    pair_id: point.pair_id ?? "—",
    quality_flag: point.quality_flag ?? "unknown",
    ...point.values,
  }));

  return (
    <div className="pageStack">
      <SectionHeading
        kicker="Options"
        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 }}>
              {supportsUnderlying(config) ? (
                <label>
                  Asset
                  <select value={underlying} onChange={(event) => setUnderlying(event.target.value)}>
                    {(latest?.supported_underlyings ?? ["BTC", "ETH"]).map((item) => (
                      <option key={item} value={item}>{item}</option>
                    ))}
                  </select>
                </label>
              ) : null}
              <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="insufficient_data">insufficient_data</option>
                  <option value="low_coverage">low_coverage</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 pages</h3></div>
            <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              {config.relatedSignals.map((signalId) => (
                <Link key={signalId} href={`/signals/${signalId}`} 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 }}>
                        {OPTIONS_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 supportsUnderlying(config: OptionsDashboardConfig) {
  return config.relatedSignals.length > 0 && !["cross_asset_rv", "btc_eth_dispersion"].includes(config.id);
}

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

function PlaybookPanel({ config }: { config: OptionsDashboardConfig }) {
  return (
    <div className="playbookPanel">
      <p style={{ color: "var(--muted)", fontSize: 12 }}>{config.playbook.whatItMeasures}</p>
      <PlaybookList title="Interpretation" items={config.playbook.interpretation} />
      <PlaybookList title="Trade expressions" items={config.playbook.tradeExpressions} />
      <PlaybookList title="Caveats" items={config.playbook.caveats} />
      <PlaybookList title="Check next" items={config.playbook.companionChecks} />
    </div>
  );
}

function PlaybookList({ title, items }: { title: string; items: string[] }) {
  return (
    <div className="playbookSection">
      <p className="eyebrow">{title}</p>
      <ul className="playbookList">
        {items.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
}
