import { useState, useEffect, useRef, useCallback } from 'react';
import { UpbitTickerResponse, MarketTicker, MarketInfo } from '../types/ticker';
import { WebSocketStatus } from '../types/orderbook';
import axios from 'axios';
import { getApiBaseUrl } from '../services/apiConfig';

const UPBIT_WS_URL = 'wss://api.upbit.com/websocket/v1';
const RECONNECT_DELAY = 3000;

/**
 * 업비트 실시간 티커(현재가) Hook
 */
export const useUpbitTicker = () => {
  const [tickers, setTickers] = useState<Map<string, MarketTicker>>(new Map());
  const [markets, setMarkets] = useState<MarketInfo[]>([]);
  const [wsStatus, setWsStatus] = useState<WebSocketStatus>('disconnected');
  
  const wsRef = useRef<WebSocket | null>(null);
  const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const isConnectingRef = useRef(false);
  // 최신 markets를 항상 참조하기 위한 ref (stale closure 방지)
  const marketsRef = useRef<MarketInfo[]>([]);
  marketsRef.current = markets;

  /**
   * 마켓 목록 가져오기 (백엔드 API 사용)
   */
  const fetchMarkets = useCallback(async () => {
    try {
      const apiBaseUrl = getApiBaseUrl();
      const response = await axios.get<Array<{ symbol: string; koreanName: string; englishName: string }>>(
        `${apiBaseUrl}/crypto/list`,
        { timeout: 10000 }
      );
      
      // MarketInfo 형식으로 변환
      const krwMarkets: MarketInfo[] = response.data
        .filter(m => m.symbol.startsWith('KRW-'))
        .map(m => ({
          market: m.symbol,
          korean_name: m.koreanName,
          english_name: m.englishName,
        }));
      
      setMarkets(krwMarkets);
      
      console.log('[Ticker] Loaded markets:', krwMarkets.length);
      return krwMarkets;
    } catch (error) {
      console.error('[Ticker] Failed to fetch markets:', error);
      return [];
    }
  }, []);

  /**
   * 티커 데이터 처리
   */
  const processTickerData = useCallback((data: UpbitTickerResponse) => {
    const symbol = data.code.split('-')[1]; // KRW-BTC -> BTC
    // marketsRef를 사용해 항상 최신 markets를 참조 (stale closure 방지)
    const marketInfo = marketsRef.current.find(m => m.market === data.code);
    
    const ticker: MarketTicker = {
      code: data.code,
      symbol: symbol,
      koreanName: marketInfo?.korean_name || symbol,
      englishName: marketInfo?.english_name || symbol,
      tradePrice: data.trade_price,
      change: data.change,
      changeRate: data.signed_change_rate * 100, // 소수를 퍼센트로
      changePrice: data.signed_change_price,
      accTradePrice24h: data.acc_trade_price_24h,
      timestamp: data.timestamp,
    };

    setTickers(prev => {
      const newTickers = new Map(prev);
      newTickers.set(data.code, ticker);
      return newTickers;
    });
  }, []); // marketsRef는 ref이므로 의존성 불필요

  /**
   * WebSocket 연결
   */
  const connect = useCallback((marketCodes: string[]) => {
    if (isConnectingRef.current || (wsRef.current && wsRef.current.readyState === WebSocket.OPEN)) {
      return;
    }

    if (marketCodes.length === 0) {
      console.log('[Ticker] No markets to subscribe');
      return;
    }

    isConnectingRef.current = true;
    setWsStatus('connecting');

    try {
      const ws = new WebSocket(UPBIT_WS_URL);
      ws.binaryType = 'arraybuffer';
      
      ws.onopen = () => {
        console.log('[Ticker] WebSocket connected');
        isConnectingRef.current = false;
        setWsStatus('connected');
        
        // 구독 메시지 전송 (모든 KRW 마켓)
        const subscribeMessage = [
          { ticket: `ticker-${Date.now()}` },
          {
            type: 'ticker',
            codes: marketCodes,
            isOnlyRealtime: true,
          },
        ];
        
        ws.send(JSON.stringify(subscribeMessage));
        console.log('[Ticker] Subscribed to', marketCodes.length, 'markets');
      };

      ws.onmessage = async (event: MessageEvent) => {
        try {
          let text: string;
          
          if (typeof event.data === 'string') {
            text = event.data;
          } else if (event.data instanceof ArrayBuffer) {
            text = new TextDecoder('utf-8').decode(event.data);
          } else if (event.data instanceof Blob) {
            text = await event.data.text();
          } else {
            return;
          }
          
          const data: UpbitTickerResponse = JSON.parse(text);
          
          if (data.type === 'ticker') {
            processTickerData(data);
          }
        } catch (error) {
          // 티커는 빈번하게 오므로 에러 로그 최소화
          if (Math.random() < 0.01) { // 1%만 로그
            console.error('[Ticker] Failed to parse message');
          }
        }
      };

      ws.onerror = (error) => {
        console.error('[Ticker] WebSocket error:', error);
        isConnectingRef.current = false;
        setWsStatus('error');
      };

      ws.onclose = () => {
        console.log('[Ticker] WebSocket closed');
        isConnectingRef.current = false;
        setWsStatus('disconnected');
        
        // 자동 재연결
        reconnectTimeoutRef.current = setTimeout(() => {
          console.log('[Ticker] Attempting to reconnect...');
          if (marketCodes.length > 0) {
            connect(marketCodes);
          }
        }, RECONNECT_DELAY);
      };

      wsRef.current = ws;
    } catch (error) {
      console.error('[Ticker] Failed to create WebSocket:', error);
      isConnectingRef.current = false;
      setWsStatus('error');
    }
  }, [processTickerData]);

  /**
   * WebSocket 연결 해제
   */
  const disconnect = useCallback(() => {
    if (reconnectTimeoutRef.current) {
      clearTimeout(reconnectTimeoutRef.current);
      reconnectTimeoutRef.current = null;
    }

    if (wsRef.current) {
      const ws = wsRef.current;
      ws.onopen = null;
      ws.onmessage = null;
      ws.onerror = null;
      ws.onclose = null;
      
      if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
        ws.close();
      }
      
      wsRef.current = null;
    }

    isConnectingRef.current = false;
    setWsStatus('disconnected');
  }, []);

  /**
   * 초기화
   */
  useEffect(() => {
    const initMarkets = async () => {
      const marketList = await fetchMarkets();
      if (marketList.length > 0) {
        const marketCodes = marketList.map(m => m.market);
        connect(marketCodes);
      }
    };

    initMarkets();

    return () => {
      disconnect();
    };
  }, []); // 최초 한 번만 실행

  // markets가 변경되면 재연결
  useEffect(() => {
    if (markets.length > 0 && wsStatus === 'disconnected') {
      const marketCodes = markets.map(m => m.market);
      connect(marketCodes);
    }
  }, [markets, wsStatus]);

  // markets 로드 후 기존 tickers의 koreanName 업데이트
  useEffect(() => {
    if (markets.length === 0) return;
    setTickers(prev => {
      if (prev.size === 0) return prev;
      const updated = new Map(prev);
      let changed = false;
      updated.forEach((ticker, code) => {
        const marketInfo = markets.find(m => m.market === code);
        if (marketInfo && ticker.koreanName === ticker.symbol) {
          updated.set(code, { ...ticker, koreanName: marketInfo.korean_name, englishName: marketInfo.english_name });
          changed = true;
        }
      });
      return changed ? updated : prev;
    });
  }, [markets]);

  return {
    tickers,
    markets,
    wsStatus,
    connect,
    disconnect,
  };
};
