'use client';

import { useEffect, useState, useCallback, useRef, useMemo } from 'react';
import { useSignalRContext } from '@/contexts/signalrProvider';
import { fetchApi } from '@/lib/utils/client';
import type { CandleData, CandleRestData, CandleBar, VolumeBar, MAData, TickerData } from '@/types/crypto';

type IntervalType = 'sec' | '1' | '3' | '5' | '10' | '15' | '30' | '60' | '240' | 'day' | 'week' | 'month';

const UP_COLOR = 'rgba(239, 83, 80, 0.5)';
const DOWN_COLOR = 'rgba(66, 133, 244, 0.5)';

function toUnixTime(dateStr: string): number {
	return Math.floor(new Date(dateStr).getTime() / 1000);
}

function getEndpointForInterval(market: string, interval: IntervalType, count: number): string {
	switch (interval) {
		case 'sec':
			return `/api/crypto/${market}/candles/seconds?count=${count}`;
		case 'day':
			return `/api/crypto/${market}/candles/days?count=${count}`;
		case 'week':
			return `/api/crypto/${market}/candles/weeks?count=${count}`;
		case 'month':
			return `/api/crypto/${market}/candles/months?count=${count}`;
		default:
			return `/api/crypto/${market}/candles/minutes/${interval}?count=${count}`;
	}
}

export default function useCandles(market: string, interval: IntervalType = '1') {
	const { cryptoConnection, cryptoConnected } = useSignalRContext();
	const [candles, setCandles] = useState<CandleBar[]>([]);
	const [volumes, setVolumes] = useState<VolumeBar[]>([]);
	const [loading, setLoading] = useState(true);
	const candlesRef = useRef<CandleBar[]>([]);
	const volumesRef = useRef<VolumeBar[]>([]);
	const tickerUpdateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

	// REST 초기 로드
	useEffect(() => {
		if (!market) {
			return;
		}

		setLoading(true);
		candlesRef.current = [];
		volumesRef.current = [];

		const load = async () => {
			try {
				const endpoint = getEndpointForInterval(market, interval, 200);
				const res = await fetchApi<CandleRestData[]>(endpoint);
				if (res.success && res.data) {
					const sorted = [...res.data].sort((a, b) =>
						toUnixTime(a.candleDateTimeUtc) - toUnixTime(b.candleDateTimeUtc)
					);

					const bars: CandleBar[] = sorted.map((c) => ({
						time: toUnixTime(c.candleDateTimeUtc),
						open: c.openingPrice,
						high: c.highPrice,
						low: c.lowPrice,
						close: c.tradePrice,
					}));

					const vols: VolumeBar[] = sorted.map((c) => ({
						time: toUnixTime(c.candleDateTimeUtc),
						value: c.candleAccTradeVolume,
						color: c.tradePrice >= c.openingPrice ? UP_COLOR : DOWN_COLOR,
					}));

					candlesRef.current = bars;
					volumesRef.current = vols;
					setCandles(bars);
					setVolumes(vols);
				}
			} catch (error) {
				console.error('Failed to load candles:', error);
			} finally {
				setLoading(false);
			}
		};

		load();
	}, [market, interval]);

	// SignalR 실시간 캔들 업데이트 (1분봉만)
	const handleCandle = useCallback((data: CandleData) => {
		if (data.market !== market || interval !== '1') {
			return;
		}

		const time = toUnixTime(data.candleDateTimeUtc);
		const bar: CandleBar = {
			time,
			open: data.openingPrice,
			high: data.highPrice,
			low: data.lowPrice,
			close: data.tradePrice,
		};

		const vol: VolumeBar = {
			time,
			value: data.candleAccTradeVolume,
			color: data.tradePrice >= data.openingPrice ? UP_COLOR : DOWN_COLOR,
		};

		const bars = [...candlesRef.current];
		const vols = [...volumesRef.current];
		const lastIdx = bars.length - 1;

		if (lastIdx >= 0 && bars[lastIdx].time === time) {
			bars[lastIdx] = bar;
			vols[lastIdx] = vol;
		} else {
			bars.push(bar);
			vols.push(vol);
		}

		candlesRef.current = bars;
		volumesRef.current = vols;
		setCandles(bars);
		setVolumes(vols);
	}, [market, interval]);

	// SignalR 실시간 티커 → 마지막 캔들 close 업데이트 (모든 인터벌)
	const scheduleTickerUpdate = useCallback(() => {
		if (tickerUpdateTimerRef.current) {
			return;
		}
		tickerUpdateTimerRef.current = setTimeout(() => {
			setCandles([...candlesRef.current]);
			setVolumes([...volumesRef.current]);
			tickerUpdateTimerRef.current = null;
		}, 250);
	}, []);

	const handleTicker = useCallback((ticker: TickerData) => {
		if (ticker.market !== market || candlesRef.current.length === 0) {
			return;
		}

		const bars = candlesRef.current;
		const vols = volumesRef.current;
		const lastIdx = bars.length - 1;
		const last = bars[lastIdx];

		if (interval === 'sec') {
			// 초봉: 새로운 초가 되면 새 캔들 바 생성
			const nowSec = Math.floor(ticker.timestamp / 1000);
			if (nowSec !== last.time) {
				bars.push({
					time: nowSec,
					open: ticker.tradePrice,
					high: ticker.tradePrice,
					low: ticker.tradePrice,
					close: ticker.tradePrice,
				});
				vols.push({
					time: nowSec,
					value: 0,
					color: UP_COLOR,
				});
			} else {
				bars[lastIdx] = {
					...last,
					close: ticker.tradePrice,
					high: Math.max(last.high, ticker.tradePrice),
					low: Math.min(last.low, ticker.tradePrice),
				};
				vols[lastIdx] = {
					...vols[lastIdx],
					color: ticker.tradePrice >= last.open ? UP_COLOR : DOWN_COLOR,
				};
			}
		} else {
			// 분봉 이상: 마지막 캔들 close/high/low 업데이트
			bars[lastIdx] = {
				...last,
				close: ticker.tradePrice,
				high: Math.max(last.high, ticker.tradePrice),
				low: Math.min(last.low, ticker.tradePrice),
			};
			vols[lastIdx] = {
				...vols[lastIdx],
				color: ticker.tradePrice >= last.open ? UP_COLOR : DOWN_COLOR,
			};
		}

		scheduleTickerUpdate();
	}, [market, interval, scheduleTickerUpdate]);

	useEffect(() => {
		if (!cryptoConnection || !cryptoConnected) {
			return;
		}

		cryptoConnection.on('ReceiveCandle', handleCandle);
		cryptoConnection.on('ReceiveTicker', handleTicker);

		return () => {
			cryptoConnection.off('ReceiveCandle', handleCandle);
			cryptoConnection.off('ReceiveTicker', handleTicker);
			if (tickerUpdateTimerRef.current) {
				clearTimeout(tickerUpdateTimerRef.current);
				tickerUpdateTimerRef.current = null;
			}
		};
	}, [cryptoConnection, cryptoConnected, handleCandle, handleTicker]);

	// MA 계산
	const ma5 = useMemo(() => calcMA(candles, 5), [candles]);
	const ma10 = useMemo(() => calcMA(candles, 10), [candles]);
	const ma20 = useMemo(() => calcMA(candles, 20), [candles]);

	return { candles, volumes, ma5, ma10, ma20, loading };
}

function calcMA(data: CandleBar[], period: number): MAData[] {
	if (data.length < period) return [];
	const result: MAData[] = [];
	let sum = 0;
	for (let i = 0; i < data.length; i++) {
		sum += data[i].close;
		if (i >= period) {
			sum -= data[i - period].close;
		}
		if (i >= period - 1) {
			result.push({ time: data[i].time, value: sum / period });
		}
	}
	return result;
}