/**
 * 실시간 호가 — 증권앱형 통합 레이아웃
 * 상단 시세 · 서브탭 · 매도/현재가/매수 테이블 · 우측 시세 · 좌측 체결 · 하단 합계
 */
import React, { memo, useState, useEffect } from 'react';
import { formatNowClock, useDisplayTimezone } from '../utils/timezone';
import type { OrderbookDisplayUnit, WsStatus } from '../hooks/useUpbitOrderbook';
import type { RecentTrade } from '../hooks/useUpbitRecentTrades';
import { getKoreanName } from '../utils/marketNameCache';

function fmtPrice(p: number): string {
  if (p == null || !isFinite(p)) return '-';
  if (p >= 1_000) return p.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
  if (p >= 1) return p.toFixed(2);
  return p.toFixed(6);
}

function fmtSize(s: number): string {
  if (s == null || !isFinite(s)) return '-';
  if (s >= 1_000_000) return s.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
  if (s >= 1_000) return s.toLocaleString('ko-KR', { maximumFractionDigits: 2 });
  if (s >= 1) return s.toFixed(4);
  return s.toFixed(6);
}

function fmtTradeVol(v: number): string {
  if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(2)}M`;
  if (v >= 1_000) return Math.round(v).toLocaleString('ko-KR');
  return v.toFixed(4);
}

function fmtPct(price: number, prevClose: number): string {
  if (!prevClose) return '';
  const rate = ((price - prevClose) / prevClose) * 100;
  return `${rate >= 0 ? '+' : ''}${rate.toFixed(2)}%`;
}

function fmtTotalSize(s: number): string {
  if (s >= 1_000) return s.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
  if (s >= 1) return s.toFixed(2);
  return s.toFixed(4);
}

function coinCode(market: string): string {
  return market.replace(/^KRW-/, '');
}

function pctClass(pct: string): string {
  if (pct.startsWith('+')) return 'ob-td-pct--up';
  if (pct.startsWith('-')) return 'ob-td-pct--dn';
  return '';
}

function useClock(): string {
  const tz = useDisplayTimezone();
  const [t, setT] = useState(() => formatNowClock(tz, true));
  useEffect(() => {
    const tick = () => setT(formatNowClock(tz, true));
    tick();
    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, [tz]);
  return t;
}

const COLGROUP = (
  <colgroup>
    <col className="ob-col-side" />
    <col className="ob-col-price" />
    <col className="ob-col-side" />
  </colgroup>
);

const AskTableRow = memo(function AskTableRow({
  unit, prevClose, onClick,
}: {
  unit: OrderbookDisplayUnit;
  prevClose: number;
  onClick?: (price: number, type: 'ask' | 'bid') => void;
}) {
  const pct = fmtPct(unit.price, prevClose);
  return (
    <tr className={onClick ? 'ob-tr--clickable' : undefined} onClick={onClick ? () => onClick(unit.price, 'ask') : undefined}>
      <td className="ob-td ob-td-qty ob-td-qty--ask">
        <div className="ob-td-bar-wrap">
          <div className="ob-td-bar ob-td-bar--ask" style={{ width: `${Math.min(unit.percentage, 100)}%` }} />
          <span className="ob-td-bar-text">{fmtSize(unit.size)}</span>
        </div>
      </td>
      <td className="ob-td ob-td-price">{fmtPrice(unit.price)}</td>
      <td className={`ob-td ob-td-pct ${pctClass(pct)}`}>{pct}</td>
    </tr>
  );
});

/** 가격은 항상 가운데 열 — 매수: 전일대비(좌) | 가격 | 잔량(우) */
const BidTableRow = memo(function BidTableRow({
  unit, prevClose, onClick,
}: {
  unit: OrderbookDisplayUnit;
  prevClose: number;
  onClick?: (price: number, type: 'ask' | 'bid') => void;
}) {
  const pct = fmtPct(unit.price, prevClose);
  return (
    <tr className={onClick ? 'ob-tr--clickable' : undefined} onClick={onClick ? () => onClick(unit.price, 'bid') : undefined}>
      <td className={`ob-td ob-td-pct ob-td-pct--left ${pctClass(pct)}`}>{pct}</td>
      <td className="ob-td ob-td-price">{fmtPrice(unit.price)}</td>
      <td className="ob-td ob-td-qty ob-td-qty--bid">
        <div className="ob-td-bar-wrap ob-td-bar-wrap--right">
          <div className="ob-td-bar ob-td-bar--bid" style={{ width: `${Math.min(unit.percentage, 100)}%` }} />
          <span className="ob-td-bar-text">{fmtSize(unit.size)}</span>
        </div>
      </td>
    </tr>
  );
});

function QuoteHeader({
  market, tickerInfo, prevClose, totalAskSize, totalBidSize, wsStatus,
}: {
  market: string;
  tickerInfo?: OrderbookTickerInfo;
  prevClose: number;
  totalAskSize: number;
  totalBidSize: number;
  wsStatus: WsStatus;
}) {
  const price = tickerInfo?.tradePrice ?? 0;
  const change = price > 0 && prevClose > 0 ? price - prevClose : (tickerInfo?.changePrice ?? 0);
  const rate = tickerInfo?.changeRate != null
    ? tickerInfo.changeRate * 100
    : (prevClose > 0 && price > 0 ? (change / prevClose) * 100 : 0);
  const isUp = change >= 0;
  const vol = tickerInfo?.accTradeVolume24 ?? 0;
  const bidRatio = totalAskSize + totalBidSize > 0
    ? (totalBidSize / (totalAskSize + totalBidSize)) * 100
    : 50;
  const code = coinCode(market);

  return (
    <div className="ob-quote-header">
      <div className="ob-quote-left">
        <span className="ob-quote-name">{getKoreanName(market)}</span>
        <div className="ob-quote-price-row">
          <span className={`ob-quote-price ${isUp ? 'ob-quote-price--up' : 'ob-quote-price--dn'}`}>
            {price > 0 ? fmtPrice(price) : '-'}
          </span>
          <span className={`ob-quote-change ${isUp ? 'ob-quote-change--up' : 'ob-quote-change--dn'}`}>
            {change >= 0 ? '+' : ''}{Math.abs(change) >= 1000
              ? Math.round(change).toLocaleString('ko-KR')
              : change.toFixed(change >= 1 ? 0 : 2)}
          </span>
          <span className={`ob-quote-rate ${isUp ? 'ob-quote-rate--up' : 'ob-quote-rate--dn'}`}>
            {rate >= 0 ? '+' : ''}{rate.toFixed(2)}%
          </span>
        </div>
      </div>
      <div className="ob-quote-right">
        <div className="ob-quote-vol">
          <span className="ob-quote-vol-label">거래량</span>
          <span className="ob-quote-vol-val">
            {vol > 0 ? `${Math.round(vol).toLocaleString('ko-KR')} ${code}` : '-'}
          </span>
        </div>
        <div className="ob-quote-ratio">
          <span className="ob-quote-ratio-label">매수비</span>
          <span className="ob-quote-ratio-val ob-quote-ratio-val--up">{bidRatio.toFixed(2)}%</span>
        </div>
        <WsDot status={wsStatus} />
      </div>
    </div>
  );
}

function WsDot({ status }: { status: WsStatus }) {
  const cls = status === 'connected' ? 'ob-dot--ok'
    : status === 'connecting' ? 'ob-dot--wait' : 'ob-dot--err';
  return <span className={`ob-dot ${cls}`}><span className="ob-dot-circle" /></span>;
}

function StatsRail({ tickerInfo, prevClose }: {
  tickerInfo: OrderbookTickerInfo;
  prevClose: number;
}) {
  return (
    <aside className="ob-stats-rail">
      <div className="ob-stat-row"><span className="ob-stat-k">전일</span><span className="ob-stat-v">{prevClose > 0 ? fmtPrice(prevClose) : '-'}</span></div>
      <div className="ob-stat-row"><span className="ob-stat-k">시가</span><span className="ob-stat-v">{tickerInfo.openingPrice != null ? fmtPrice(tickerInfo.openingPrice) : '-'}</span></div>
      <div className="ob-stat-row"><span className="ob-stat-k">고가</span><span className="ob-stat-v ob-stat-v--up">{tickerInfo.highPrice != null ? fmtPrice(tickerInfo.highPrice) : '-'}</span></div>
      <div className="ob-stat-row"><span className="ob-stat-k">저가</span><span className="ob-stat-v ob-stat-v--dn">{tickerInfo.lowPrice != null ? fmtPrice(tickerInfo.lowPrice) : '-'}</span></div>
    </aside>
  );
}

function TradesPanel({ trades, strength }: { trades: RecentTrade[]; strength: number | null }) {
  return (
    <aside className="ob-trades-panel">
      <div className="ob-trades-strength">
        <span className="ob-trades-strength-k">체결강도</span>
        <span className={`ob-trades-strength-v${strength != null && strength >= 100 ? ' ob-trades-strength-v--up' : ''}`}>
          {strength != null ? `${strength >= 100 ? '+' : ''}${strength.toFixed(2)}%` : '-'}
        </span>
      </div>
      <table className="ob-table ob-table--trades">
        <thead><tr><th>체결가</th><th>체결량</th></tr></thead>
        <tbody>
          {trades.length === 0 ? (
            <tr><td colSpan={2} className="ob-td-empty">—</td></tr>
          ) : trades.map((t, i) => (
            <tr key={`${t.time}-${i}`}>
              <td className="ob-td ob-td-price-sm">{fmtPrice(t.price)}</td>
              <td className={t.side === 'bid' ? 'ob-td ob-trades-vol--buy' : 'ob-td ob-trades-vol--sell'}>
                {fmtTradeVol(t.volume)}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </aside>
  );
}

export interface OrderbookTickerInfo {
  tradePrice: number | null;
  changeRate: number | null;
  changePrice?: number | null;
  accTradePrice24: number;
  accTradeVolume24?: number | null;
  highPrice: number | null;
  lowPrice: number | null;
  openingPrice: number | null;
}

export interface OrderbookPanelProps {
  market: string;
  asks: OrderbookDisplayUnit[];
  bids: OrderbookDisplayUnit[];
  totalAskSize: number;
  totalBidSize: number;
  wsStatus: WsStatus;
  bestAsk: number;
  bestBid: number;
  spread: number;
  spreadPct: number;
  prevClose: number;
  tickerInfo?: OrderbookTickerInfo;
  recentTrades?: RecentTrade[];
  tradeStrength?: number | null;
  onRowClick?: (price: number, rowType: 'ask' | 'bid') => void;
}

const SUB_TABS = ['호가', '체결', '일별', '차트'] as const;

export const OrderbookPanel = memo(function OrderbookPanel({
  market, asks, bids, totalAskSize, totalBidSize, wsStatus,
  prevClose, tickerInfo, recentTrades = [], tradeStrength = null, onRowClick,
}: OrderbookPanelProps) {
  const isEmpty = asks.length === 0 && bids.length === 0;
  const midPrice = tickerInfo?.tradePrice ?? 0;
  const midPct = midPrice > 0 ? fmtPct(midPrice, prevClose) : '';
  const clock = useClock();
  const isUp = (tickerInfo?.changeRate ?? 0) >= 0;

  return (
    <div className="ob-panel ob-panel--classic">
      <QuoteHeader
        market={market}
        tickerInfo={tickerInfo}
        prevClose={prevClose}
        totalAskSize={totalAskSize}
        totalBidSize={totalBidSize}
        wsStatus={wsStatus}
      />

      <nav className="ob-subtabs" aria-label="호가 하위 메뉴">
        {SUB_TABS.map((label, i) => (
          <button
            key={label}
            type="button"
            className={`ob-subtab${i === 0 ? ' ob-subtab--active' : ''}`}
            disabled={i !== 0}
          >
            {label}
          </button>
        ))}
      </nav>

      {isEmpty ? (
        <div className="ob-empty">
          <div className="loading-spinner" style={{ width: 16, height: 16 }} />
          <span>호가 데이터 로딩 중...</span>
        </div>
      ) : (
        <div className="ob-body">
          {/* 매도 구간 + 우측 시세 */}
          <div className="ob-block ob-block--ask">
            <div className="ob-block-table">
              <div className="ob-table-scroll ob-table-scroll--ask">
                <table className="ob-table ob-table--hoga">
                  {COLGROUP}
                  <tbody>
                    {asks.map((unit, i) => (
                      <AskTableRow key={`ask-${unit.price}-${i}`} unit={unit} prevClose={prevClose} onClick={onRowClick} />
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
            {tickerInfo && <StatsRail tickerInfo={tickerInfo} prevClose={prevClose} />}
          </div>

          {/* 현재가 (가운데 열 정렬) */}
          <table className="ob-table ob-table--hoga ob-table--mid">
            {COLGROUP}
            <tbody>
              <tr className="ob-tr-mid">
                <td className="ob-td ob-td--pad" />
                <td className={`ob-td ob-td-price ob-td-price--current ${isUp ? 'ob-td-price--up' : 'ob-td-price--dn'}`}>
                  <span className="ob-mid-price">{midPrice > 0 ? fmtPrice(midPrice) : '-'}</span>
                  {midPct && <span className={`ob-mid-pct ${pctClass(midPct)}`}>{midPct}</span>}
                </td>
                <td className="ob-td ob-td--pad" />
              </tr>
            </tbody>
          </table>

          {/* 매수 구간 + 좌측 체결 */}
          <div className="ob-block ob-block--bid">
            <TradesPanel trades={recentTrades} strength={tradeStrength} />
            <div className="ob-block-table">
              <div className="ob-table-scroll ob-table-scroll--bid">
                <table className="ob-table ob-table--hoga">
                  {COLGROUP}
                  <tbody>
                    {bids.map((unit, i) => (
                      <BidTableRow key={`bid-${unit.price}-${i}`} unit={unit} prevClose={prevClose} onClick={onRowClick} />
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      )}

      {!isEmpty && (
        <footer className="ob-summary-bar">
          <div className="ob-summary ob-summary--ask">
            <span className="ob-summary-num">{fmtTotalSize(totalAskSize)}</span>
          </div>
          <div className="ob-summary ob-summary--time">{clock}</div>
          <div className="ob-summary ob-summary--bid">
            <span className="ob-summary-num">{fmtTotalSize(totalBidSize)}</span>
          </div>
        </footer>
      )}
    </div>
  );
});

export default OrderbookPanel;
