'use client';

import { useEffect, useRef, useState, useCallback } from 'react';
import { useSignalRContext } from '@/contexts/signalrProvider';
import { fetchApi } from '@/lib/utils/client';
import type { TickerData, TickerRestData, TickerMeta } from '@/types/crypto';

function restToTickerData(t: TickerRestData): TickerData {
	return {
		market: t.market,
		symbol: t.symbol,
		openingPrice: t.openingPrice,
		highPrice: t.highPrice,
		lowPrice: t.lowPrice,
		tradePrice: t.tradePrice,
		prevClosingPrice: t.prevClosingPrice,
		change: t.change,
		changePrice: t.changePrice,
		signedChangePrice: t.signedChangePrice,
		changeRate: t.changeRate,
		signedChangeRate: t.signedChangeRate,
		tradeVolume: t.tradeVolume,
		accTradeVolume: t.accTradeVolume,
		accTradeVolume24h: t.accTradeVolume24h,
		accTradePrice: t.accTradePrice,
		accTradePrice24h: t.accTradePrice24h,
		tradeDate: '',
		tradeTime: '',
		tradeTimestamp: 0,
		askBid: '',
		accAskVolume: 0,
		accBidVolume: 0,
		highest52WeekPrice: 0,
		highest52WeekDate: '',
		lowest52WeekPrice: 0,
		lowest52WeekDate: '',
		marketState: 'ACTIVE',
		delistingDate: null,
		marketWarning: '',
		timestamp: 0,
		streamType: '',
	};
}

function extractMeta(t: TickerRestData): TickerMeta {
	return {
		korName: t.korName,
		engName: t.engName,
		logoImage: t.logoImage,
	};
}

export default function useTickers(quoteMarket: string = 'KRW', initialTickers?: TickerRestData[]) {
	const { cryptoConnection, cryptoConnected } = useSignalRContext();
	const [tickers, setTickers] = useState<Map<string, TickerData>>(new Map());
	const [meta, setMeta] = useState<Map<string, TickerMeta>>(new Map());
	const tickersRef = useRef<Map<string, TickerData>>(new Map());
	const metaRef = useRef<Map<string, TickerMeta>>(new Map());
	const updateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
	const subscribedQuoteRef = useRef<string | null>(null);
	const initializedRef = useRef(false);

	// 초기 REST 데이터 로드
	useEffect(() => {
		// initialTickers는 KRW일 때만 사용 (서버에서 KRW로 패칭)
		if (!initializedRef.current && initialTickers && initialTickers.length > 0 && quoteMarket === 'KRW') {
			const tickerMap = new Map<string, TickerData>();
			const metaMap = new Map<string, TickerMeta>();
			for (const t of initialTickers) {
				tickerMap.set(t.market, restToTickerData(t));
				metaMap.set(t.market, extractMeta(t));
			}
			tickersRef.current = tickerMap;
			metaRef.current = metaMap;
			setTickers(new Map(tickerMap));
			setMeta(new Map(metaMap));
			initializedRef.current = true;
		} else {
			loadTickers(quoteMarket);
		}
	}, [quoteMarket]);

	const loadTickers = async (quote: string) => {
		try {
			const res = await fetchApi<TickerRestData[]>(`/api/crypto/tickers?quote=${quote}`);
			if (res.success && res.data) {
				const tickerMap = new Map<string, TickerData>();
				const metaMap = new Map<string, TickerMeta>();
				for (const t of res.data) {
					tickerMap.set(t.market, restToTickerData(t));
					metaMap.set(t.market, extractMeta(t));
				}
				tickersRef.current = tickerMap;
				metaRef.current = metaMap;
				setTickers(new Map(tickerMap));
				setMeta(new Map(metaMap));
				initializedRef.current = true;
			}
		} catch (error) {
			console.error('Failed to load tickers:', error);
		}
	};

	// 배치 업데이트 (250ms 간격)
	const scheduleUpdate = useCallback(() => {
		if (updateTimerRef.current) {
			return;
		}
		updateTimerRef.current = setTimeout(() => {
			setTickers(new Map(tickersRef.current));
			updateTimerRef.current = null;
		}, 250);
	}, []);

	// SignalR 구독
	useEffect(() => {
		if (!cryptoConnection || !cryptoConnected) {
			return;
		}

		const handleTicker = (ticker: TickerData) => {
			tickersRef.current.set(ticker.market, ticker);
			scheduleUpdate();
		};

		const handleTickers = (list: TickerData[]) => {
			for (const ticker of list) {
				tickersRef.current.set(ticker.market, ticker);
			}
			scheduleUpdate();
		};

		// 이전 구독 해제
		if (subscribedQuoteRef.current && subscribedQuoteRef.current !== quoteMarket) {
			cryptoConnection.invoke('UnsubscribeTickers', subscribedQuoteRef.current).catch(() => {});
		}

		cryptoConnection.on('ReceiveTicker', handleTicker);
		cryptoConnection.on('ReceiveTickers', handleTickers);
		cryptoConnection.invoke('SubscribeTickers', quoteMarket).catch(console.error);
		subscribedQuoteRef.current = quoteMarket;

		return () => {
			cryptoConnection.off('ReceiveTicker', handleTicker);
			cryptoConnection.off('ReceiveTickers', handleTickers);
			if (subscribedQuoteRef.current) {
				cryptoConnection.invoke('UnsubscribeTickers', subscribedQuoteRef.current).catch(() => {});
				subscribedQuoteRef.current = null;
			}
			if (updateTimerRef.current) {
				clearTimeout(updateTimerRef.current);
				updateTimerRef.current = null;
			}
		};
	}, [cryptoConnection, cryptoConnected, quoteMarket, scheduleUpdate]);

	return { tickers, meta };
}