"use client";

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

import { CandlestickChart } from "@/components/candlestick-chart";
import { SectionHeading } from "@/components/section-heading";
import { SignalLineChart } from "@/components/line-chart";
import { StatusBadge } from "@/components/status-badge";
import { getCompositeSignalLatest, getCompositeSignalSeries, getPriceSeries } from "@/lib/api/client";
import type { CompositeSignalSeriesResponse, CompositeSignalSummary, PriceSeriesResponse } from "@/lib/api/types";
import { formatMetricValue, formatTimestamp } from "@/lib/format";
import { rangeWindowIso, seriesMaxPoints } from "@/lib/ranges";

const TIMEFRAMES = ["1m", "5m", "15m", "1h", "4h"] as const;
const VENUE_SCOPES = ["binance", "bybit", "all"] as const;
const REQUEST_TIMEOUT_MS = 8000;
const AUTO_REFRESH_MS = 60_000;
const COMPOSITE_RANGE_DAYS = 7;

function defaultStart(timeframe: (typeof TIMEFRAMES)[number]) {
  const now = new Date();
  const start = new Date(now);
  if (timeframe === "1m" || timeframe === "5m" || timeframe === "15m") {
    start.setUTCDate(start.getUTCDate() - 1);
  } else if (timeframe === "1h") {
    start.setUTCDate(start.getUTCDate() - 7);
  } else {
    start.setUTCDate(start.getUTCDate() - 30);
  }
  return start.toISOString();
}

export function MarketOverview() {
  const [asset, setAsset] = useState<"BTC" | "ETH">("BTC");
  const [venueScope, setVenueScope] = useState<(typeof VENUE_SCOPES)[number]>("binance");
  const [timeframe, setTimeframe] = useState<(typeof TIMEFRAMES)[number]>("15m");
  const [series, setSeries] = useState<PriceSeriesResponse | null>(null);
  const [compositeLatest, setCompositeLatest] = useState<CompositeSignalSummary | null>(null);
  const [compositeSeries, setCompositeSeries] = useState<CompositeSignalSeriesResponse | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [compositeLoading, setCompositeLoading] = useState<boolean>(true);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [compositeError, setCompositeError] = useState<string | null>(null);
  const requestTokenRef = useRef(0);
  const compositeRequestTokenRef = useRef(0);

  async function refresh(nextAsset: "BTC" | "ETH", nextVenueScope: (typeof VENUE_SCOPES)[number], nextTimeframe: (typeof TIMEFRAMES)[number]) {
    const token = ++requestTokenRef.current;
    const controller = new AbortController();
    const timer = window.setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
    setIsLoading(true);
    setLoadError(null);
    try {
      const nextSeries = await getPriceSeries(
        nextAsset,
        nextVenueScope,
        nextTimeframe,
        defaultStart(nextTimeframe),
        undefined,
        240,
        controller.signal,
      );
      if (requestTokenRef.current !== token) {
        return;
      }
      if (!nextSeries) {
        setLoadError("Market data is temporarily unavailable.");
        return;
      }
      setSeries(nextSeries);
    } catch {
      if (requestTokenRef.current === token) {
        setLoadError("Market data request timed out.");
      }
    } finally {
      window.clearTimeout(timer);
      if (requestTokenRef.current === token) {
        setIsLoading(false);
      }
    }
  }

  useEffect(() => {
    void refresh(asset, venueScope, timeframe);
  }, [asset, venueScope, timeframe]);

  useEffect(() => {
    const handle = window.setInterval(() => {
      void refresh(asset, venueScope, timeframe);
    }, AUTO_REFRESH_MS);
    return () => window.clearInterval(handle);
  }, [asset, venueScope, timeframe]);

  async function refreshComposite() {
    const token = ++compositeRequestTokenRef.current;
    const controller = new AbortController();
    const timer = window.setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
    setCompositeLoading(true);
    setCompositeError(null);
    try {
      const nextLatest = await getCompositeSignalLatest("market_composite", controller.signal);
      if (compositeRequestTokenRef.current !== token) {
        return;
      }
      const { start, end } = rangeWindowIso(COMPOSITE_RANGE_DAYS, nextLatest?.latest_updated_at);
      const nextSeries = await getCompositeSignalSeries(
        "market_composite",
        start,
        end,
        undefined,
        seriesMaxPoints(COMPOSITE_RANGE_DAYS),
        controller.signal,
      );
      if (compositeRequestTokenRef.current !== token) {
        return;
      }
      if (!nextLatest || !nextSeries) {
        setCompositeError("Composite index is temporarily unavailable.");
        return;
      }
      setCompositeLatest(nextLatest);
      setCompositeSeries(nextSeries);
    } catch {
      if (compositeRequestTokenRef.current === token) {
        setCompositeError("Composite index request timed out.");
      }
    } finally {
      window.clearTimeout(timer);
      if (compositeRequestTokenRef.current === token) {
        setCompositeLoading(false);
      }
    }
  }

  useEffect(() => {
    void refreshComposite();
  }, []);

  useEffect(() => {
    const handle = window.setInterval(() => {
      void refreshComposite();
    }, AUTO_REFRESH_MS);
    return () => window.clearInterval(handle);
  }, []);

  const latest = series?.latest_values ?? {};
  const pointCount = series?.points.length ?? 0;
  const latestPointTs = series?.points.at(-1)?.ts ?? null;
  const latestAvailableAt =
    typeof series?.context?.latest_available_at === "string" ? series.context.latest_available_at : latestPointTs;
  const aggregationMode =
    typeof series?.context?.aggregation_mode === "string"
      ? series.context.aggregation_mode
      : venueScope === "all"
        ? "median_across_venues"
        : "preferred_venue";
  const sourceVenue =
    typeof series?.context?.source_venue === "string" ? series.context.source_venue : null;
  const latestClose = typeof latest.close === "number" ? latest.close : null;
  const latestOpen = typeof latest.open === "number" ? latest.open : null;
  const moveSinceOpen =
    latestClose != null && latestOpen != null && latestOpen !== 0
      ? ((latestClose - latestOpen) / latestOpen) * 100
      : null;
  const compositeChartData = useMemo(
    () =>
      (compositeSeries?.points ?? []).map((point) => ({
        ts: point.ts,
        ...point.values,
      })),
    [compositeSeries],
  );
  const compositeMetrics = compositeLatest?.latest_values ?? {};
  const compositeMetricRows: Array<{ label: string; value: unknown }> = [
    { label: "Sentiment", value: compositeMetrics.sentiment_index },
    { label: "Directional", value: compositeMetrics.directional_tilt },
    { label: "Fragility", value: compositeMetrics.fragility_index },
    { label: "Confidence", value: compositeMetrics.confidence_score },
  ];
  const dataLagMinutes =
    latestAvailableAt != null
      ? Math.max(0, Math.round((Date.now() - new Date(latestAvailableAt).getTime()) / 60_000))
      : null;
  const isSeriesStale = Boolean(series?.context?.stale) || (dataLagMinutes != null && dataLagMinutes > 30);
  const latestContextRows: Array<{ label: string; value: unknown }> = [
    { label: "Last", value: latestClose },
    { label: "Move", value: moveSinceOpen },
    { label: "Open", value: latest.open as number | null | undefined },
    { label: "High", value: latest.high as number | null | undefined },
    { label: "Low", value: latest.low as number | null | undefined },
    { label: "Close", value: latest.close as number | null | undefined },
    { label: "Volume", value: latest.volume as number | null | undefined },
  ];

  return (
    <div className="pageStack">
      <SectionHeading
        kicker="Overview"
        title="Market candles"
        description="BTC and ETH price action from live microstructure bars."
      />

      <div className="panel">
        <div className="panelHeader" style={{ alignItems: "flex-start" }}>
          <div>
            <h3>{asset} candlestick view</h3>
            <span style={{ fontSize: 12, color: "var(--text-dim)" }}>
              {venueScope === "all"
                ? "Market-wide synthetic OHLCV from `microstructure_bar` using median venue aggregation."
                : `Preferred ${venueScope} feed from \`microstructure_bar\`${sourceVenue ? ` (${sourceVenue})` : ""}.`}
            </span>
          </div>
          <div style={{ display: "flex", gap: 8, flexWrap: "wrap", justifyContent: "flex-end" }}>
            <div className="tabBar" style={{ borderBottom: "none", marginBottom: 0 }}>
              {(["BTC", "ETH"] as const).map((symbol) => (
                <button
                  key={symbol}
                  className={`tabItem ${asset === symbol ? "tabActive" : ""}`}
                  onClick={() => setAsset(symbol)}
                >
                  {symbol}
                </button>
              ))}
            </div>
            <div className="tabBar" style={{ borderBottom: "none", marginBottom: 0 }}>
              {VENUE_SCOPES.map((value) => (
                <button
                  key={value}
                  className={`tabItem ${venueScope === value ? "tabActive" : ""}`}
                  onClick={() => setVenueScope(value)}
                >
                  {value}
                </button>
              ))}
            </div>
            <div className="tabBar" style={{ borderBottom: "none", marginBottom: 0 }}>
              {TIMEFRAMES.map((value) => (
                <button
                  key={value}
                  className={`tabItem ${timeframe === value ? "tabActive" : ""}`}
                  onClick={() => setTimeframe(value)}
                >
                  {value}
                </button>
              ))}
            </div>
          </div>
        </div>
        {loadError ? (
          <div className="chartEmpty">
            <p className="eyebrow">{loadError}</p>
          </div>
        ) : isLoading && !series ? (
          <div className="chartEmpty">
            <p className="eyebrow">Loading candles…</p>
          </div>
        ) : (
          <CandlestickChart points={series?.points ?? []} timeframe={timeframe} />
        )}
      </div>

      <div className="chartGrid">
        <div className="panel">
          <div className="panelHeader">
            <div>
              <h3>{asset} latest candle</h3>
              <span style={{ fontSize: 12, color: "var(--text-dim)" }}>
                Cards below are for the latest loaded candle. Hover the chart for historical candles.
              </span>
            </div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))", gap: 12 }}>
            {latestContextRows.map((item) => (
              <div key={item.label} className="panel" style={{ padding: 12 }}>
                <div className="eyebrow">{item.label}</div>
                <div style={{ marginTop: 6, fontSize: 22, fontWeight: 700, color: "var(--text-primary)" }}>
                  {typeof item.value === "number" ? formatMetricValue(item.value, item.label.toLowerCase()) : "—"}
                </div>
              </div>
            ))}
          </div>
        </div>

        <div className="panel">
          <div className="panelHeader" style={{ alignItems: "flex-start" }}>
            <div>
              <h3>Market composite index</h3>
              <span style={{ fontSize: 12, color: "var(--text-dim)" }}>
                Top-down market state from BTC/ETH composite signals.
              </span>
            </div>
            <Link className="tabItem" href="/composite/composite_market">
              open
            </Link>
          </div>
          {compositeError ? (
            <div className="chartEmpty">
              <p className="eyebrow">{compositeError}</p>
            </div>
          ) : compositeLoading && !compositeSeries ? (
            <div className="chartEmpty">
              <p className="eyebrow">Loading composite index…</p>
            </div>
          ) : (
            <>
              <SignalLineChart
                data={compositeChartData}
                lines={[
                  { key: "sentiment_index", label: "Sentiment", color: "#6ac2ff", yAxisId: "left" },
                  { key: "fragility_index", label: "Fragility", color: "#f58549", yAxisId: "left" },
                  { key: "directional_tilt", label: "Directional", color: "#8dd3c7", yAxisId: "right" },
                ]}
                dualAxis
                height={240}
                loading={compositeLoading}
              />
              <div style={{ display: "grid", gridTemplateColumns: "repeat(4, minmax(0, 1fr))", gap: 10, marginTop: 12 }}>
                {compositeMetricRows.map((metric) => (
                  <div key={metric.label} className="surfaceCard">
                    <div className="eyebrow">{metric.label}</div>
                    <div style={{ marginTop: 6, fontSize: 20, fontWeight: 700, color: "var(--text-primary)" }}>
                      {typeof metric.value === "number" ? formatMetricValue(metric.value, metric.label.toLowerCase()) : "—"}
                    </div>
                  </div>
                ))}
              </div>
            </>
          )}
        </div>

        <div className="panel">
          <div className="panelHeader"><h3>Series status</h3></div>
          <div style={{ display: "grid", gap: 12 }}>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16 }}>
              <span className="eyebrow">Asset</span>
              <strong>{asset}</strong>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16 }}>
              <span className="eyebrow">Timeframe</span>
              <strong>{timeframe}</strong>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16 }}>
              <span className="eyebrow">Latest price update</span>
              <strong>{formatTimestamp(latestAvailableAt)}</strong>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16 }}>
              <span className="eyebrow">Latest candle opens</span>
              <strong>{formatTimestamp(latestPointTs)}</strong>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16 }}>
              <span className="eyebrow">Data lag</span>
              <strong>
                {dataLagMinutes == null
                  ? "—"
                  : dataLagMinutes < 60
                    ? `${dataLagMinutes}m`
                    : `${Math.floor(dataLagMinutes / 60)}h ${dataLagMinutes % 60}m`}
              </strong>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16 }}>
              <span className="eyebrow">Candles loaded</span>
              <strong>{pointCount}</strong>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16, alignItems: "center" }}>
              <span className="eyebrow">Load state</span>
              <StatusBadge
                label={loadError ? "error" : isLoading ? "loading" : isSeriesStale ? "stale" : "live"}
                tone={loadError ? "warn" : isLoading ? "neutral" : isSeriesStale ? "warn" : "ok"}
              />
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16, alignItems: "center" }}>
              <span className="eyebrow">Venue scope</span>
              <StatusBadge label={series?.venue_scope ?? venueScope} tone="neutral" />
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16, alignItems: "center" }}>
              <span className="eyebrow">Aggregation</span>
              <StatusBadge
                label={aggregationMode}
                tone="neutral"
              />
            </div>
            {sourceVenue ? (
              <div style={{ display: "flex", justifyContent: "space-between", gap: 16, alignItems: "center" }}>
                <span className="eyebrow">Source venue</span>
                <StatusBadge label={sourceVenue} tone="neutral" />
              </div>
            ) : null}
            <div style={{ display: "flex", justifyContent: "space-between", gap: 16, alignItems: "center" }}>
              <span className="eyebrow">Composite state</span>
              <StatusBadge
                label={compositeError ? "error" : compositeLoading ? "loading" : compositeLatest?.latest_quality ?? "live"}
                tone={compositeError ? "warn" : compositeLoading ? "neutral" : "ok"}
              />
            </div>
            {loadError ? (
              <div style={{ display: "grid", gap: 8 }}>
                <p className="eyebrow" style={{ color: "var(--accent-warn)" }}>
                  {loadError}
                </p>
                <button
                  className="tabItem"
                  style={{ width: "fit-content" }}
                  onClick={() => {
                    void refresh(asset, venueScope, timeframe);
                  }}
                >
                  Retry
                </button>
              </div>
            ) : null}
            {compositeError ? (
              <div style={{ display: "grid", gap: 8 }}>
                <p className="eyebrow" style={{ color: "var(--accent-warn)" }}>
                  {compositeError}
                </p>
                <button
                  className="tabItem"
                  style={{ width: "fit-content" }}
                  onClick={() => {
                    void refreshComposite();
                  }}
                >
                  Retry composite
                </button>
              </div>
            ) : null}
          </div>
        </div>
      </div>
    </div>
  );
}
