"use client";

import { useEffect, useRef } from "react";
import {
  createChart,
  type CandlestickData,
  type IChartApi,
  type ISeriesApi,
  type LineData,
  type UTCTimestamp,
} from "lightweight-charts";
import type { ChartPayload, LatestPredictionResponse } from "../lib/api";

type Props = {
  chart: ChartPayload;
  prediction?: LatestPredictionResponse | null;
};

// 'YYYY-MM-DD' 또는 'YYYY-MM-DDTHH:MM:SS' (KST naive, 백엔드가 +09:00 시각의 wall-clock 을
// 그대로 ISO 로 직렬화) 를 UTCTimestamp 로. lightweight-charts 는 timestamp 가 UTC 라고
// 가정하지만, 우리는 KST wall-clock 을 UTC 인 척 넣는다 — timeScale 의 표시도 KST 그대로
// 나와서 한국 사용자에겐 가장 직관적.
function isoToUtcTs(s: string): UTCTimestamp {
  if (s.length <= 10) {
    return (Date.UTC(
      Number(s.slice(0, 4)),
      Number(s.slice(5, 7)) - 1,
      Number(s.slice(8, 10)),
    ) / 1000) as UTCTimestamp;
  }
  // datetime: YYYY-MM-DDTHH:MM:SS
  return (Date.UTC(
    Number(s.slice(0, 4)),
    Number(s.slice(5, 7)) - 1,
    Number(s.slice(8, 10)),
    Number(s.slice(11, 13)),
    Number(s.slice(14, 16)),
    Number(s.slice(17, 19) || "0"),
  ) / 1000) as UTCTimestamp;
}

export function StockChart({ chart, prediction }: Props) {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const chartRef = useRef<IChartApi | null>(null);
  const candleRef = useRef<ISeriesApi<"Candlestick"> | null>(null);
  const predRef = useRef<ISeriesApi<"Line"> | null>(null);
  const predLowRef = useRef<ISeriesApi<"Line"> | null>(null);
  const predHighRef = useRef<ISeriesApi<"Line"> | null>(null);

  const isIntraday = chart.interval === "10m";

  // create chart once (interval 바뀌면 timeVisible 토글 위해 의존성에 isIntraday 포함 — 재생성)
  useEffect(() => {
    if (!containerRef.current) return;
    const c = createChart(containerRef.current, {
      layout: {
        background: { color: "transparent" },
        textColor: "#cbd5e1",
      },
      grid: {
        vertLines: { color: "#1f2937" },
        horzLines: { color: "#1f2937" },
      },
      rightPriceScale: { borderColor: "#374151" },
      timeScale: {
        borderColor: "#374151",
        timeVisible: isIntraday,
        secondsVisible: false,
      },
      autoSize: true,
    });
    const candle = c.addCandlestickSeries({
      upColor: "#22c55e",
      downColor: "#ef4444",
      borderUpColor: "#22c55e",
      borderDownColor: "#ef4444",
      wickUpColor: "#22c55e",
      wickDownColor: "#ef4444",
    });
    chartRef.current = c;
    candleRef.current = candle;
    return () => {
      c.remove();
      chartRef.current = null;
      candleRef.current = null;
      predRef.current = null;
      predLowRef.current = null;
      predHighRef.current = null;
    };
  }, [isIntraday]);

  // push candle data + today marker
  useEffect(() => {
    if (!candleRef.current) return;
    const data: CandlestickData[] = chart.ohlcv
      .filter((p) => p.open !== null && p.high !== null && p.low !== null && p.close !== null)
      .map((p) => ({
        time: isoToUtcTs(p.date),
        open: p.open as number,
        high: p.high as number,
        low: p.low as number,
        close: p.close as number,
      }));
    candleRef.current.setData(data);
    // 오늘 표시는 차트 본체 위가 아니라 컨테이너 아래 캡션 (return JSX) 으로 옮김.
    // lightweight-charts 의 timeScale tick 자체에 라벨을 끼울 공식 API 가 없어서,
    // 시각적으로 동일한 위치 (시간축 바로 아래) 에 별도 div 로 렌더.
    chartRef.current?.timeScale().fitContent();
  }, [chart, isIntraday]);

  // push prediction overlay (10분봉에서는 표시 안 함 — 예측은 일봉 기준)
  useEffect(() => {
    if (!chartRef.current) return;
    if (predRef.current) {
      chartRef.current.removeSeries(predRef.current);
      predRef.current = null;
    }
    if (predLowRef.current) {
      chartRef.current.removeSeries(predLowRef.current);
      predLowRef.current = null;
    }
    if (predHighRef.current) {
      chartRef.current.removeSeries(predHighRef.current);
      predHighRef.current = null;
    }
    if (isIntraday) return;
    if (!prediction || !prediction.found || !prediction.steps?.length) return;
    const baseDate = prediction.base_date!;
    const baseClose = prediction.base_close;
    if (!baseClose) return;
    const sorted = [...prediction.steps].sort((a, b) => a.horizon - b.horizon);

    const med: LineData[] = [
      { time: isoToUtcTs(baseDate), value: baseClose },
      ...sorted
        .filter((s) => s.point_close !== null)
        .map((s) => ({ time: isoToUtcTs(s.target_date), value: s.point_close as number })),
    ];
    const lo: LineData[] = [
      { time: isoToUtcTs(baseDate), value: baseClose },
      ...sorted
        .filter((s) => s.ci_low !== null)
        .map((s) => ({ time: isoToUtcTs(s.target_date), value: s.ci_low as number })),
    ];
    const hi: LineData[] = [
      { time: isoToUtcTs(baseDate), value: baseClose },
      ...sorted
        .filter((s) => s.ci_high !== null)
        .map((s) => ({ time: isoToUtcTs(s.target_date), value: s.ci_high as number })),
    ];

    const medLine = chartRef.current.addLineSeries({
      color: "#a78bfa",
      lineWidth: 2,
      lineStyle: 2, // dashed
      priceLineVisible: false,
      lastValueVisible: true,
      title: "예측 median",
    });
    medLine.setData(med);
    const loLine = chartRef.current.addLineSeries({
      color: "#7c3aed",
      lineWidth: 1,
      lineStyle: 1,
      priceLineVisible: false,
      lastValueVisible: false,
      title: "q10",
    });
    loLine.setData(lo);
    const hiLine = chartRef.current.addLineSeries({
      color: "#7c3aed",
      lineWidth: 1,
      lineStyle: 1,
      priceLineVisible: false,
      lastValueVisible: false,
      title: "q90",
    });
    hiLine.setData(hi);
    predRef.current = medLine;
    predLowRef.current = loLine;
    predHighRef.current = hiLine;
    chartRef.current.timeScale().fitContent();
  }, [prediction, isIntraday]);

  // 오늘 라벨 — 차트 본체에 마커 대신 시간축 바로 아래에 작은 캡션으로.
  // 10분봉은 데이터 자체가 오늘 하루라 굳이 라벨 불필요.
  const todayLabel =
    !isIntraday && chart.today
      ? new Date(chart.today + "T00:00:00").toLocaleDateString("ko-KR", {
          year: "numeric",
          month: "2-digit",
          day: "2-digit",
          weekday: "short",
        })
      : null;

  return (
    <div className="w-full rounded-md border border-zinc-800 bg-zinc-900/30 p-2">
      <div className="h-[460px] w-full">
        <div ref={containerRef} className="h-full w-full" />
      </div>
      {todayLabel && (
        <div className="mt-1 flex items-center justify-end gap-2 px-2 text-xs text-zinc-400">
          <span className="inline-block h-2 w-2 rounded-full bg-amber-400" />
          <span>오늘 · {todayLabel}</span>
        </div>
      )}
    </div>
  );
}
