"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";

import { SignalLineChart } from "@/components/line-chart";
import { SectionHeading } from "@/components/section-heading";
import { StatusBadge } from "@/components/status-badge";
import { addWidgetToDashboards } from "@/lib/dashboards";
import { getPerpsDashboardSeries } from "@/lib/api/client";
import { formatMetricValue, formatTimestamp } from "@/lib/format";
import { rangeWindowIso, seriesMaxPoints } from "@/lib/ranges";
import type { PerpsDashboardResponse, PerpsDashboardSummary } from "@/lib/api/types";
import { useStream } from "@/lib/ws/use-stream";

import { PERPS_DASHBOARDS } from "./perps-config";

function fmtVal(v: unknown, key?: string): string {
  if (v == null) return "—";
  if (typeof v === "number") return formatMetricValue(v, key);
  return String(v);
}

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

export function PerpsList({ dashboards }: { dashboards: PerpsDashboardSummary[] }) {
  const router = useRouter();
  const [pinnedIds, setPinnedIds] = useState<Set<string>>(new Set());
  const [seriesMap, setSeriesMap] = useState<Map<string, PerpsDashboardResponse>>(new Map());
  const [assetMap, setAssetMap] = useState<Map<string, string>>(() => {
    const m = new Map<string, string>();
    for (const d of dashboards) m.set(d.id, d.supported_assets[0] ?? "BTC");
    return m;
  });
  const [scopeMap, setScopeMap] = useState<Map<string, string>>(() => {
    const m = new Map<string, string>();
    for (const d of dashboards) m.set(d.id, d.supported_venue_scopes[0] ?? "all");
    return m;
  });
  const [loadingIds, setLoadingIds] = useState<Set<string>>(new Set());
  const requestIdsRef = useRef<Map<string, number>>(new Map());
  const abortControllersRef = useRef<Map<string, AbortController>>(new Map());

  const pinnedRef = useRef(pinnedIds);
  pinnedRef.current = pinnedIds;
  const assetRef = useRef(assetMap);
  assetRef.current = assetMap;
  const scopeRef = useRef(scopeMap);
  scopeRef.current = scopeMap;

  const fetchSeries = useCallback(async (dashboardId: string, asset: string, venueScope: string) => {
    abortControllersRef.current.get(dashboardId)?.abort();
    const controller = new AbortController();
    abortControllersRef.current.set(dashboardId, controller);
    const requestId = (requestIdsRef.current.get(dashboardId) ?? 0) + 1;
    requestIdsRef.current.set(dashboardId, requestId);
    setLoadingIds((prev) => new Set(prev).add(dashboardId));
    const latestUpdatedAt = dashboards.find((dashboard) => dashboard.id === dashboardId)?.latest_updated_at;
    const { start, end } = rangeWindowIso(1, latestUpdatedAt);
    const result = await getPerpsDashboardSeries(
      dashboardId,
      asset,
      venueScope,
      start,
      end,
      undefined,
      seriesMaxPoints(1),
      controller.signal,
    );
    if (!controller.signal.aborted && requestIdsRef.current.get(dashboardId) === requestId && result) {
      setSeriesMap((prev) => new Map(prev).set(dashboardId, result));
    }
    if (abortControllersRef.current.get(dashboardId) === controller) {
      abortControllersRef.current.delete(dashboardId);
    }
    if (requestIdsRef.current.get(dashboardId) === requestId) {
      setLoadingIds((prev) => {
        const next = new Set(prev);
        next.delete(dashboardId);
        return next;
      });
    }
  }, [dashboards]);

  useEffect(() => {
    return () => {
      for (const controller of abortControllersRef.current.values()) {
        controller.abort();
      }
      abortControllersRef.current.clear();
    };
  }, []);

  const togglePin = useCallback((dashboard: PerpsDashboardSummary) => {
    setPinnedIds((prev) => {
      const next = new Set(prev);
      if (next.has(dashboard.id)) {
        next.delete(dashboard.id);
      } else {
        next.add(dashboard.id);
        void fetchSeries(
          dashboard.id,
          assetRef.current.get(dashboard.id) ?? "BTC",
          scopeRef.current.get(dashboard.id) ?? "all",
        );
      }
      return next;
    });
  }, [fetchSeries]);

  useStream((event) => {
    if (event.event === "dataset.updated" || event.event === "signal.updated") {
      for (const id of pinnedRef.current) {
        void fetchSeries(id, assetRef.current.get(id) ?? "BTC", scopeRef.current.get(id) ?? "all");
      }
    }
  });

  const pinnedDashboards = dashboards.filter((dashboard) => pinnedIds.has(dashboard.id));

  return (
    <div className="pageStack">
      <SectionHeading
        kicker="Perps"
        title="Perps analytics workbench"
        description="Click rows to pin charts. Double-click to open the detailed workspace."
      />
      <div className="panel">
        <div className="panelHeader">
          <h3>Dashboards</h3>
          <span style={{ fontSize: 11, color: "var(--text-dim)" }}>
            click to pin chart · double-click for workspace
          </span>
        </div>
        <div className="tableWrap">
          <table className="dataTable">
            <thead>
              <tr>
                <th style={{ width: 28 }}></th>
                <th>Dashboard</th>
                <th>Assets</th>
                <th>Primary</th>
                <th>Secondary</th>
                <th>Tertiary</th>
                <th>Quality</th>
                <th>Updated</th>
                <th>Dashboards</th>
              </tr>
            </thead>
            <tbody>
              {dashboards.map((dashboard) => {
                const entries = Object.entries(dashboard.latest_values ?? {}).slice(0, 3);
                const isPinned = pinnedIds.has(dashboard.id);
                return (
                  <tr
                    key={dashboard.id}
                    className={`rowClickable ${isPinned ? "rowActive" : ""}`}
                    onClick={() => togglePin(dashboard)}
                    onDoubleClick={() => router.push(`/perps/${dashboard.id}`)}
                  >
                    <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)" }} />
                    </td>
                    <td><strong>{dashboard.name}</strong></td>
                    <td>{dashboard.supported_assets.join(", ")}</td>
                    <td>{entries[0] ? `${labelize(entries[0][0])}: ${fmtVal(entries[0][1], entries[0][0])}` : "—"}</td>
                    <td>{entries[1] ? `${labelize(entries[1][0])}: ${fmtVal(entries[1][1], entries[1][0])}` : "—"}</td>
                    <td>{entries[2] ? `${labelize(entries[2][0])}: ${fmtVal(entries[2][1], entries[2][0])}` : "—"}</td>
                    <td><StatusBadge label={dashboard.latest_quality ?? "unknown"} tone={dashboard.latest_quality === "ok" ? "ok" : "warn"} /></td>
                    <td>{formatTimestamp(dashboard.latest_updated_at)}</td>
                    <td>
                      <button
                        className="tabItem"
                        onClick={(event) => {
                          event.stopPropagation();
                          addWidgetToDashboards({
                            kind: "chart",
                            family: "perps",
                            sourceId: dashboard.id,
                            title: dashboard.name,
                            filters: {
                              asset: dashboard.supported_assets[0] ?? "BTC",
                              venue_scope: dashboard.supported_venue_scopes[0] ?? "all",
                            },
                            colSpan: 6,
                            rowSpan: 1,
                          });
                        }}
                      >
                        add
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>

      {pinnedDashboards.length > 0 && (
        <div className="chartGrid">
          {pinnedDashboards.map((dashboard) => {
            const series = seriesMap.get(dashboard.id);
            const config = PERPS_DASHBOARDS.find((item) => item.id === dashboard.id);
            const currentAsset = assetMap.get(dashboard.id) ?? "BTC";
            const currentScope = scopeMap.get(dashboard.id) ?? "all";
            return (
              <div key={dashboard.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 }}>{dashboard.name}</h3>
                    {loadingIds.has(dashboard.id) && <span className="fetchingIndicator">loading</span>}
                  </div>
                  <div style={{ display: "flex", gap: 4 }}>
                    <div className="tabBar" style={{ borderBottom: "none", marginBottom: 0 }}>
                      {dashboard.supported_assets.map((asset) => (
                        <button
                          key={asset}
                          className={`tabItem ${asset === currentAsset ? "tabActive" : ""}`}
                          onClick={() => {
                            setAssetMap((prev) => new Map(prev).set(dashboard.id, asset));
                            void fetchSeries(dashboard.id, asset, currentScope);
                          }}
                        >
                          {asset}
                        </button>
                      ))}
                    </div>
                    <select
                      value={currentScope}
                      onChange={(event) => {
                        const nextScope = event.target.value;
                        setScopeMap((prev) => new Map(prev).set(dashboard.id, nextScope));
                        void fetchSeries(dashboard.id, currentAsset, nextScope);
                      }}
                    >
                      {dashboard.supported_venue_scopes.map((scope) => (
                        <option key={scope} value={scope}>{scope}</option>
                      ))}
                    </select>
                  </div>
                </div>
                <SignalLineChart
                  data={(series?.points ?? []).map((point) => ({ ts: point.ts, ...point.values }))}
                  lines={config?.lines ?? []}
                  dualAxis={config?.dualAxis}
                />
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}
