"use client";

// 호가창 — 10단계 매도/매수 호가 + 잔량. Toss 톤의 한 줄 한 줄 막대 그래프.
// /api/orderbook/{code} 폴링 (10s). 키 없으면 안내 카드.
//
// 표시 규칙:
//   - 위쪽: 매도호가 10개 (가장 낮은 askp1 이 맨 아래, 즉 현재가에 인접)
//     → 그래서 화면상 askp10 → askp1 (위에서 아래로 가격 내림차순) 으로 렌더
//   - 가운데 굵게: 현재가 + 전일대비 + %
//   - 아래쪽: 매수호가 10개 (가장 높은 bidp1 이 맨 위, bidp10 이 맨 아래)
//   - 잔량 막대: 매도/매수 각각의 단계별 최대잔량 기준 비율로 색상 막대.
//   - 색상: 매도=파랑(하락 톤), 매수=빨강(상승 톤) — 한국 거래소 관행.

import { useEffect, useState } from "react";
import { api, type OrderbookLevel, type OrderbookResponse } from "../lib/api";

type Props = {
  code: string;
  // 1D(10분봉) 모드일 때만 sticky 로 띄움 — 종목 페이지가 길어 스크롤해도 매수/매도 호가가
  // 시야에 남도록. 일봉 이상에선 호가의 실시간 가치가 낮아 일반 흐름으로 두는 게 사이드바
  // 다른 패널(PriceTargets/AlertsPanel/InvestmentNote/RelatedStocks) 의 위치 안정성을 해치지
  // 않음.
  sticky?: boolean;
};

const POLL_MS = 10_000;

export function OrderbookPanel({ code, sticky = false }: Props) {
  const [data, setData] = useState<OrderbookResponse | null>(null);
  const [err, setErr] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let alive = true;
    const load = () => {
      api
        .orderbook(code)
        .then((r) => {
          if (!alive) return;
          setData(r);
          setErr(null);
          setLoading(false);
        })
        .catch((e) => {
          if (!alive) return;
          setErr(e instanceof Error ? e.message : String(e));
          setLoading(false);
        });
    };
    load();
    const h = window.setInterval(load, POLL_MS);
    return () => {
      alive = false;
      window.clearInterval(h);
    };
  }, [code]);

  return (
    <div
      className={
        sticky
          ? "sticky top-4 rounded-md border border-zinc-800 bg-zinc-900/80 p-3 backdrop-blur"
          : "rounded-md border border-zinc-800 bg-zinc-900/40 p-3"
      }
    >
      <div className="mb-2 flex items-center justify-between gap-2">
        <span className="text-xs font-medium text-zinc-300">호가</span>
        <span className="text-[10px] text-zinc-500">
          {data?.ts ? `${data.ts} · 10초 갱신` : "10초 갱신"}
        </span>
      </div>

      {loading && !data && (
        <div className="py-6 text-center text-[11px] text-zinc-500">불러오는 중…</div>
      )}

      {err && !data && (
        <div className="rounded border border-rose-800/40 bg-rose-900/10 p-2 text-[11px] text-rose-300">
          호가 로딩 실패: {err}
        </div>
      )}

      {data?.status === "skipped_missing_key" && (
        <div className="rounded border border-amber-800/40 bg-amber-900/10 p-2 text-[11px] text-amber-200">
          KIS API 키가 설정되지 않아 호가를 표시할 수 없습니다.
        </div>
      )}

      {data && data.status === "ok" && <OrderbookTable data={data} />}
    </div>
  );
}

function OrderbookTable({ data }: { data: OrderbookResponse }) {
  // KIS 가 항상 10단계를 다 주진 않을 수 있어 정렬 강제.
  // 매도: level 오름차순 (1=가장 낮은 매도) → 화면은 level 내림차순으로 표시.
  // 매수: level 오름차순 (1=가장 높은 매수) → 화면은 level 오름차순.
  const asks = [...data.asks].sort((a, b) => a.level - b.level);
  const bids = [...data.bids].sort((a, b) => a.level - b.level);
  const asksDesc = [...asks].reverse();

  // 잔량 막대 정규화 — 매도/매수 통틀어 max 로 정규화하면 한쪽이 항상 미니 막대로 나옴.
  // 사이드별 max 로 각자 정규화.
  const askMax = Math.max(1, ...asks.map((x) => x.qty));
  const bidMax = Math.max(1, ...bids.map((x) => x.qty));

  const change = data.prev_close_diff ?? 0;
  const tone =
    change > 0 ? "text-rose-400" : change < 0 ? "text-sky-400" : "text-zinc-400";

  return (
    <div className="space-y-1">
      <ul className="space-y-0.5">
        {asksDesc.map((lv) => (
          <Row key={`a${lv.level}`} lv={lv} max={askMax} side="ask" />
        ))}
      </ul>

      <div className="my-1 flex items-center justify-between rounded bg-zinc-800/60 px-2 py-1.5">
        <span className="text-[10px] text-zinc-400">현재가</span>
        <div className="flex items-baseline gap-2">
          <span className="text-base font-semibold tabular-nums text-zinc-50">
            {data.current != null ? data.current.toLocaleString() : "—"}
          </span>
          {data.prev_close_diff != null && (
            <span className={`text-[11px] tabular-nums ${tone}`}>
              {change > 0 ? "+" : ""}
              {change.toLocaleString()}
              {data.prev_close_pct != null && (
                <span className="ml-0.5">
                  ({data.prev_close_pct > 0 ? "+" : ""}
                  {data.prev_close_pct.toFixed(2)}%)
                </span>
              )}
            </span>
          )}
        </div>
      </div>

      <ul className="space-y-0.5">
        {bids.map((lv) => (
          <Row key={`b${lv.level}`} lv={lv} max={bidMax} side="bid" />
        ))}
      </ul>

      <div className="mt-1.5 flex items-center justify-between border-t border-zinc-800 pt-1.5 text-[10px] text-zinc-500">
        <span>매도 합 {data.ask_total.toLocaleString()}</span>
        <span>매수 합 {data.bid_total.toLocaleString()}</span>
      </div>
    </div>
  );
}

function Row({
  lv,
  max,
  side,
}: {
  lv: OrderbookLevel;
  max: number;
  side: "ask" | "bid";
}) {
  const pct = Math.min(100, (lv.qty / max) * 100);
  // ask=파랑(하락 톤), bid=빨강(상승 톤). 잔량 막대는 잔량 셀 안에서 자라남:
  // - ask 행: 가격(좌) · 잔량(우) — 막대는 잔량 셀 오른쪽 → 왼쪽 (수치쪽으로) 자라남
  // - bid 행: 잔량(좌) · 가격(우) — 막대는 잔량 셀 왼쪽 → 오른쪽 자라남
  const barColor = side === "ask" ? "bg-sky-500/20" : "bg-rose-500/20";
  const priceColor = side === "ask" ? "text-sky-300" : "text-rose-300";

  const priceCell = (
    <span className={`tabular-nums ${priceColor}`}>{lv.price.toLocaleString()}</span>
  );
  const qtyCell = (
    <span className="relative inline-block w-full overflow-hidden rounded-sm py-0.5">
      <span
        className={`absolute inset-y-0 ${side === "ask" ? "right-0" : "left-0"} ${barColor}`}
        style={{ width: `${pct}%` }}
        aria-hidden
      />
      <span
        className={`relative z-10 block tabular-nums text-zinc-300 ${
          side === "ask" ? "text-right" : "text-left"
        } px-1.5`}
      >
        {lv.qty.toLocaleString()}
      </span>
    </span>
  );

  return (
    <li className="grid grid-cols-[12px_64px_1fr] items-center gap-1.5 text-[11px]">
      <span className="text-[9px] text-zinc-600">{lv.level}</span>
      <span className="text-right">{priceCell}</span>
      {qtyCell}
    </li>
  );
}
