"use client";

import { useEffect, useRef } from "react";
import {
  createChart,
  type CandlestickData,
  type IChartApi,
  type ISeriesApi,
  type LineData,
  type SeriesMarker,
  type Time,
  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);

    // 오늘 날짜 마커: 일/주/월봉에서만 표시 (10분봉은 데이터 자체가 오늘 하루라 무의미).
    // markers 는 데이터 포인트의 time 과 일치해야 표시되므로, 오늘 또는 가장 가까운 과거
    // 거래일을 찾는다.
    if (!isIntraday && chart.today) {
      const todayTs = isoToUtcTs(chart.today);
      // 차트의 마지막 데이터가 오늘이면 그 위에, 아니면 마지막 데이터 위에 "오늘" 표시.
      const lastTs = data.length > 0 ? (data[data.length - 1].time as UTCTimestamp) : null;
      const markerTime = (lastTs && lastTs <= todayTs ? lastTs : todayTs) as UTCTimestamp;
      const markers: SeriesMarker<Time>[] = [
        {
          time: markerTime,
          position: "aboveBar",
          color: "#fbbf24",
          shape: "arrowDown",
          text: "오늘",
        },
      ];
      candleRef.current.setMarkers(markers);
    } else {
      candleRef.current.setMarkers([]);
    }
    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]);

  return (
    <div className="h-[460px] w-full rounded-md border border-zinc-800 bg-zinc-900/30 p-2">
      <div ref={containerRef} className="h-full w-full" />
    </div>
  );
}
