import React, { useState, useEffect, useCallback, useRef } from 'react';
import { setMarketNames } from '../utils/marketNameCache';
import {
  getFavorites,
  toggleFavorite,
  FAVORITES_CHANGED_EVENT,
} from '../utils/marketStorage';
import { API_BASE } from '../utils/backendApi';
import { UPBIT_API } from '../utils/upbitApi';
import { fetchTickersThrottled } from '../utils/upbitTickerFetch';
import { useIsCompactDevice } from '../hooks/useMediaQuery';
import { safeToFixed } from '../utils/safeFormat';
import { VirtualScroll } from './common/VirtualScroll';

// ─── Types ───────────────────────────────────────────────────────────────────
interface MarketInfo {
  market:       string;   // "KRW-BTC"
  korean_name:  string;   // "비트코인"
  english_name: string;   // "Bitcoin"
  symbol:       string;   // "BTC"
}

interface TickerInfo {
  trade_price:          number;
  signed_change_rate:   number;   // 전일 대비 변화율 (소수, e.g. 0.015 = +1.5%)
  acc_trade_price_24h:  number;   // 24h 거래대금 (KRW)
}

// ─── Constants ───────────────────────────────────────────────────────────────
const TICKER_TTL_DESKTOP = 5000;
const TICKER_TTL_COMPACT = 25_000;

function formatVol(vol: number | string | null | undefined): string {
  const v = Number(vol);
  if (!Number.isFinite(v)) return '-';
  if (v >= 1e12) return `${(v / 1e12).toFixed(1)}조`;
  if (v >= 1e8)  return `${(v / 1e8).toFixed(0)}억`;
  if (v >= 1e4)  return `${(v / 1e4).toFixed(0)}만`;
  return v.toLocaleString();
}

function formatChangeRate(raw: number | string | null | undefined): number | null {
  const rate = Number(raw);
  if (!Number.isFinite(rate)) return null;
  return rate * 100;
}

// ─── Component ───────────────────────────────────────────────────────────────
interface MarketSearchPanelProps {
  currentMarket: string;
  onSelect:      (market: string) => void;
  onClose:       () => void;
  /**
   * 슬롯/버튼 rect. anchorPlacement 에 따라 패널 위치가 결정된다.
   * 없으면 기본(전체화면 좌측 고정) 위치로 표시된다.
   */
  anchorRect?:   DOMRect | null;
  /** slot=슬롯 영역 채움, dropdown=클릭 지점 아래 드롭다운 */
  anchorPlacement?: 'slot' | 'dropdown';
  /** overlay=팝업/고정패널, embedded=좌측 패널 인라인 목록 */
  variant?: 'overlay' | 'embedded';
  /** 외부 입력과 검색어 동기화 */
  initialQuery?: string;
  /** 제어형 검색어 (embedded 등 외부 input 사용 시) */
  query?: string;
  onQueryChange?: (query: string) => void;
  /** favorite=별표, add=투자대상 추가(+) */
  actionMode?: 'favorite' | 'add';
  /** actionMode=add 일 때 + 클릭 콜백 (행 선택과 분리) */
  onAdd?: (market: string, meta: { koreanName: string; englishName: string }) => void;
  /** actionMode=add 일 때 이미 추가된 종목 클릭 → 투자대상에서 제거 */
  onRemove?: (market: string) => void;
  /** 이미 추가된 종목 (add 모드에서 체크 표시·클릭 시 제거) */
  addedMarkets?: Set<string>;
  /** 투자대상 최대 개수에 도달 — 미등록 종목 추가 불가 */
  maxTargetsReached?: boolean;
}

export const MarketSearchPanel: React.FC<MarketSearchPanelProps> = ({
  currentMarket, onSelect, onClose, anchorRect, anchorPlacement = 'slot', initialQuery = '',
  variant = 'overlay', query: controlledQuery, onQueryChange,
  actionMode = 'favorite', onAdd, onRemove, addedMarkets, maxTargetsReached = false,
}) => {
  const embedded = variant === 'embedded';
  const isCompact = useIsCompactDevice();
  const tickerTtl = isCompact ? TICKER_TTL_COMPACT : TICKER_TTL_DESKTOP;
  const [markets, setMarkets] = useState<MarketInfo[]>([]);
  const [tickers, setTickers] = useState<Record<string, TickerInfo>>({});
  const [internalQuery, setInternalQuery] = useState(initialQuery);
  const query = controlledQuery ?? internalQuery;
  const setQuery = useCallback((next: string) => {
    if (controlledQuery === undefined) setInternalQuery(next);
    onQueryChange?.(next);
  }, [controlledQuery, onQueryChange]);
  const [favs,    setFavs]    = useState<Set<string>>(() => new Set(getFavorites()));
  const [loading, setLoading] = useState(true);

  const refreshFavs = useCallback(() => {
    setFavs(new Set(getFavorites()));
  }, []);

  const inputRef      = useRef<HTMLInputElement>(null);
  const tickerTimer   = useRef<ReturnType<typeof setInterval> | null>(null);
  const marketCodesRef = useRef<string>('');

  // ── 1. 마켓 목록 로드 ─────────────────────────────────────────────────────
  useEffect(() => {
    setLoading(true);
    fetch(`${API_BASE}/markets/all?isDetails=false`)
      .then(r => {
        if (!r.ok) return fetch(`${UPBIT_API}/market/all?isDetails=false`);
        return r;
      })
      .then(r => {
        if (!r.ok) throw new Error(`market/all ${r.status}`);
        return r.json();
      })
      .then((data: Array<{ market: string; korean_name: string; english_name: string }>) => {
        const krw = data
          .filter(m => m.market.startsWith('KRW-'))
          .map(m => ({ ...m, symbol: m.market.replace('KRW-', '') }));
        setMarkets(krw);
        marketCodesRef.current = krw.map(m => m.market).join(',');

        // 한글명 캐시 저장 (Toolbar 등에서 사용)
        const nameMap: Record<string, string> = {};
        for (const m of krw) nameMap[m.market] = m.korean_name;
        setMarketNames(nameMap);

        setLoading(false);
      })
      .catch(() => setLoading(false));

    if (!embedded) setTimeout(() => inputRef.current?.focus(), 50);
    refreshFavs();
  }, [refreshFavs, embedded]);

  useEffect(() => {
    if (controlledQuery === undefined) setInternalQuery(initialQuery);
  }, [initialQuery, controlledQuery]);

  // 좌측 마켓 패널 등에서 관심종목 변경 시 별표 동기화
  useEffect(() => {
    const onChanged = () => refreshFavs();
    window.addEventListener(FAVORITES_CHANGED_EVENT, onChanged);
    return () => window.removeEventListener(FAVORITES_CHANGED_EVENT, onChanged);
  }, [refreshFavs]);

  // ── 2. 시세 데이터 폴링 (100개씩 배치 요청) ─────────────────────────────
  const fetchTickers = useCallback(async () => {
    const codes = marketCodesRef.current;
    if (!codes) return;
    const allCodes = codes.split(',').filter(Boolean);
    const rawList = await fetchTickersThrottled(allCodes);

    setTickers(prev => {
      const map: Record<string, TickerInfo> = { ...prev };
      for (const t of rawList) {
        const market = (t.market ?? t.code) as string;
        if (!market) continue;
        map[market] = {
          trade_price: t.trade_price,
          signed_change_rate: t.signed_change_rate,
          acc_trade_price_24h: t.acc_trade_price_24h,
        };
      }
      return map;
    });
  }, []);

  useEffect(() => {
    if (markets.length === 0) return;
    fetchTickers();
    tickerTimer.current = setInterval(fetchTickers, tickerTtl);
    return () => { if (tickerTimer.current) clearInterval(tickerTimer.current); };
  }, [markets, fetchTickers, tickerTtl]);

  // ── 3. 즐겨찾기 토글 ─────────────────────────────────────────────────────
  const toggleFav = useCallback(async (market: string, e: React.MouseEvent) => {
    e.stopPropagation();
    const row = markets.find(m => m.market === market);
    try {
      const next = await toggleFavorite(market, {
        koreanName:  row?.korean_name,
        englishName: row?.english_name,
      });
      setFavs(new Set(next));
    } catch (err) {
      console.warn('[MarketSearchPanel] watchlist toggle failed', err);
    }
  }, [markets]);

  const tryAddMarket = useCallback((market: string) => {
    if (actionMode === 'add') {
      onSelect(market);
      if (addedMarkets?.has(market)) {
        if (embedded) onClose();
        return;
      }
      if (maxTargetsReached) return;
      const row = markets.find(m => m.market === market);
      onAdd?.(market, {
        koreanName: row?.korean_name ?? market,
        englishName: row?.english_name ?? market,
      });
      if (embedded) onClose();
      return;
    }
    onSelect(market);
    if (!embedded) onClose();
  }, [actionMode, onSelect, onAdd, addedMarkets, maxTargetsReached, markets, embedded, onClose]);

  const handleAddClick = useCallback((market: string, e: React.MouseEvent) => {
    e.stopPropagation();
    tryAddMarket(market);
  }, [tryAddMarket]);

  // ── 4. 필터 + 정렬 ───────────────────────────────────────────────────────
  const q = query.trim();
  const filtered = markets.filter(m => {
    if (!q) return true;
    return (
      m.korean_name.includes(q) ||
      m.symbol.toUpperCase().includes(q.toUpperCase()) ||
      m.english_name.toLowerCase().includes(q.toLowerCase()) ||
      m.market.toUpperCase().includes(q.toUpperCase())
    );
  });

  const sorted = [...filtered].sort((a, b) => {
    const fa = favs.has(a.market) ? 1 : 0;
    const fb = favs.has(b.market) ? 1 : 0;
    if (fb !== fa) return fb - fa;
    // 즐겨찾기 동순위: 24h 거래대금 내림차순
    const va = tickers[a.market]?.acc_trade_price_24h ?? 0;
    const vb = tickers[b.market]?.acc_trade_price_24h ?? 0;
    return vb - va;
  });

  // ── Render ────────────────────────────────────────────────────────────────
  // anchorRect 제공 시: 슬롯 영역 안에 패널을 위치시킨다.
  const HEADER_H = 30; // 슬롯 헤더 높이 (약 30px)
  const MIN_W    = 260;

  // LWC v5 canvas 레이어가 내부적으로 높은 z-index를 사용하므로
  // 인라인 스타일로 z-index를 명시해 패널이 항상 최상단에 렌더되게 보장한다.
  const PANEL_Z = 99999;

  const DROPDOWN_H = 480;
  const isCompactDropdown = anchorPlacement === 'dropdown' && !embedded;

  const panelStyle: React.CSSProperties | undefined = embedded
    ? undefined
    : anchorRect
      ? anchorPlacement === 'dropdown'
        ? {
            position:   'fixed',
            top:        anchorRect.bottom + 4,
            left:       anchorRect.left,
            width:      Math.max(420, anchorRect.width, MIN_W),
            height:     Math.min(DROPDOWN_H, window.innerHeight - anchorRect.bottom - 12),
            maxWidth:   Math.min(520, window.innerWidth - anchorRect.left - 8),
            minHeight:  320,
            zIndex:     PANEL_Z,
            background: 'var(--bg2)',
            color:      'var(--text)',
            border:     '1px solid var(--border)',
          }
        : {
            position:   'fixed',
            top:        anchorRect.top  + HEADER_H,
            left:       anchorRect.left,
            width:      Math.max(anchorRect.width, MIN_W),
            height:     anchorRect.height - HEADER_H,
            maxWidth:   anchorRect.width,
            zIndex:     PANEL_Z,
            background: 'var(--bg2)',
            color:      'var(--text)',
            border:     '1px solid var(--border)',
          }
      : undefined; // undefined → CSS 기본값(.msp-panel) 그대로 사용

  // backdrop: dropdown=전체 화면, slot=해당 슬롯 영역만
  const backdropStyle: React.CSSProperties | undefined = anchorRect
    ? anchorPlacement === 'dropdown'
      ? {
          position:   'fixed',
          inset:      0,
          zIndex:     PANEL_Z - 1,
          background: 'rgba(0,0,0,0.28)',
        }
      : {
          position:        'fixed',
          top:             anchorRect.top,
          left:            anchorRect.left,
          width:           anchorRect.width,
          height:          anchorRect.height,
          zIndex:          PANEL_Z - 1,
          background:      'rgba(0,0,0,0.45)',
          backdropFilter:  'none',
        }
    : undefined;

  const handleRowSelect = useCallback((market: string) => {
    tryAddMarket(market);
  }, [tryAddMarket]);

  return (
    <>
      {!embedded && (
        <div
          className="msp-backdrop"
          style={backdropStyle}
          onClick={onClose}
        />
      )}

      <div
        className={[
          'msp-panel',
          anchorRect && anchorPlacement === 'dropdown' ? 'msp-panel--dropdown' : '',
          anchorRect && anchorPlacement === 'slot' ? 'msp-panel--slot' : '',
          embedded ? 'msp-panel--embedded' : '',
        ].filter(Boolean).join(' ')}
        style={panelStyle}
      >

        {!embedded && (
        <div className="msp-search-row">
          <span className="msp-search-icon">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
            </svg>
          </span>
          <input
            ref={inputRef}
            className="msp-input"
            placeholder="종목명 또는 심볼 검색"
            value={query}
            onChange={e => setQuery(e.target.value)}
            onKeyDown={e => {
              if (e.key === 'Escape') onClose();
              if (e.key === 'Enter' && sorted.length > 0) handleRowSelect(sorted[0].market);
            }}
          />
          {query && (
            <button className="msp-btn-icon" title="초기화" onClick={() => setQuery('')}>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
                <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
              </svg>
            </button>
          )}
          <button className="msp-btn-icon" title="닫기" onClick={onClose}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
              <polyline points="18 15 12 9 6 15"/>
            </svg>
          </button>
        </div>
        )}

        <div className={`msp-header${embedded ? ' msp-header--embedded' : ''}${isCompactDropdown ? ' msp-header--compact' : ''}`}>
          {!isCompactDropdown && (
            <span className="msp-col msp-col-fav">{embedded ? '추가' : ''}</span>
          )}
          <span className="msp-col msp-col-name">{isCompactDropdown ? '종목명' : '한글명'}</span>
          {!embedded && (
            <>
              <span className="msp-col msp-col-price">현재가</span>
              <span className="msp-col msp-col-change">전일대비</span>
              {!isCompactDropdown && (
                <span className="msp-col msp-col-vol">거래대금</span>
              )}
            </>
          )}
        </div>

        {/* 목록 — 가상 스크롤 (업비트 전 종목) */}
        {loading ? (
          <div className="msp-list">
            <div className="msp-empty">마켓 목록 로딩 중...</div>
          </div>
        ) : (
          <VirtualScroll
            className="msp-list"
            items={sorted}
            estimateSize={embedded ? 34 : isCompactDropdown ? 36 : 38}
            measureDynamic
            getItemKey={m => m.market}
            empty={<div className="msp-empty">검색 결과가 없습니다</div>}
            aria-label="종목 검색 결과"
          >
            {m => {
              const tk = tickers[m.market];
              const isFav = favs.has(m.market);
              const isAdded = addedMarkets?.has(m.market) ?? false;
              const addBlocked = maxTargetsReached && !isAdded;
              const isActive = m.market === currentMarket;
              const rate = tk ? formatChangeRate(tk.signed_change_rate) : null;
              const isUp = rate !== null && rate >= 0;

              return (
                <div
                  className={[
                    'msp-item',
                    embedded ? 'msp-item--embedded' : '',
                    isCompactDropdown ? 'msp-item--compact' : '',
                    isActive ? 'active' : '',
                  ].filter(Boolean).join(' ')}
                  onClick={() => handleRowSelect(m.market)}
                >
                  {!isCompactDropdown && (
                    actionMode === 'add' ? (
                      <button
                        type="button"
                        className={`msp-add-btn${isAdded ? ' msp-add-btn--done' : ''}${addBlocked ? ' msp-add-btn--blocked' : ''}`}
                        onClick={e => handleAddClick(m.market, e)}
                        disabled={addBlocked}
                        title={
                          isAdded
                            ? '투자대상에서 제거'
                            : addBlocked
                              ? '투자대상 최대 개수에 도달했습니다'
                              : '투자대상에 추가'
                        }
                      >
                        {isAdded ? (
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
                            <polyline points="20 6 9 17 4 12"/>
                          </svg>
                        ) : (
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
                            <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
                          </svg>
                        )}
                      </button>
                    ) : (
                      <span
                        className={`msp-col msp-col-fav msp-star${isFav ? ' starred' : ''}`}
                        onClick={e => toggleFav(m.market, e)}
                        title={isFav ? '즐겨찾기 해제' : '즐겨찾기 추가'}
                      >
                        {isFav ? '★' : '☆'}
                      </span>
                    )
                  )}

                  <span className="msp-col msp-col-name">
                    <span className="msp-kor">{m.korean_name}</span>
                    {!isCompactDropdown && <span className="msp-sym">{m.symbol}</span>}
                  </span>

                  {!embedded && (
                    <>
                      <span className="msp-col msp-col-price">
                        {tk && Number.isFinite(Number(tk.trade_price))
                          ? Number(tk.trade_price).toLocaleString()
                          : '-'}
                      </span>
                      <span className={`msp-col msp-col-change ${rate === null ? '' : isUp ? 'up' : 'down'}`}>
                        {rate === null
                          ? '-'
                          : `${isUp ? '+' : ''}${safeToFixed(rate, 2)}%`}
                      </span>
                      {!isCompactDropdown && (
                        <span className="msp-col msp-col-vol">
                          {tk?.acc_trade_price_24h ? formatVol(tk.acc_trade_price_24h) : '-'}
                        </span>
                      )}
                    </>
                  )}
                </div>
              );
            }}
          </VirtualScroll>
        )}

      </div>
    </>
  );
};

export default MarketSearchPanel;
