'use client';

import { useMemo, useEffect, useRef, useState } from 'react';
import { useCryptoContext } from '@/contexts/cryptoProvider';
import useOrderbook from '@/hooks/useOrderbook';
import useTrades from '@/hooks/useTrades';
import './orderbook.scss';

interface OrderbookProps {
	playOrderbookSound: (type: 'add' | 'remove') => void;
}

function formatPrice(price: number): string {
	if (price >= 1000) {
		return price.toLocaleString('ko-KR', { maximumFractionDigits: 0 });
	}
	if (price >= 1) {
		return price.toLocaleString('ko-KR', { maximumFractionDigits: 2 });
	}
	return price.toLocaleString('ko-KR', { maximumFractionDigits: 4 });
}

function formatSize(size: number): string {
	if (size >= 1) {
		return size.toFixed(4);
	}
	return size.toFixed(6);
}

export default function Orderbook({ playOrderbookSound }: OrderbookProps) {
	const { selectedMarket, tickers } = useCryptoContext();
	const orderbook = useOrderbook(selectedMarket);
	const trades = useTrades(selectedMarket);

	// 최근 체결 가격 추적 (플래시 효과용)
	const [flashPrice, setFlashPrice] = useState<{ price: number; side: string } | null>(null);
	const prevTradeRef = useRef<number>(0);

	// 호가 가격 목록 추적 (추가/제거 감지용)
	const prevPricesRef = useRef<Set<number>>(new Set());

	// LTP 5m ago 가이드선
	const [ltp5mAgo, setLtp5mAgo] = useState<number | null>(null);
	const priceHistoryRef = useRef<{ price: number; time: number }[]>([]);

	// 현재 체결가 기록 + 5분 전 가격 계산
	const ticker = tickers.get(selectedMarket);
	useEffect(() => {
		if (!ticker) return;

		const now = Date.now();
		priceHistoryRef.current.push({ price: ticker.tradePrice, time: now });

		// 5분 이상 된 데이터 정리 (6분까지 보관)
		const cutoff = now - 6 * 60 * 1000;
		priceHistoryRef.current = priceHistoryRef.current.filter((p) => p.time > cutoff);

		// 5분 전 가격 찾기
		const fiveMinAgo = now - 5 * 60 * 1000;
		const closest = priceHistoryRef.current.reduce<{ price: number; time: number } | null>((best, p) => {
			if (p.time <= fiveMinAgo) {
				if (!best || Math.abs(p.time - fiveMinAgo) < Math.abs(best.time - fiveMinAgo)) {
					return p;
				}
			}
			return best;
		}, null);

		setLtp5mAgo(closest?.price ?? null);
	}, [ticker, selectedMarket]);

	// 마켓 변경 시 가격 기록 초기화
	useEffect(() => {
		priceHistoryRef.current = [];
		setLtp5mAgo(null);
	}, [selectedMarket]);

	// 체결 플래시 효과
	useEffect(() => {
		if (trades.length === 0) return;
		const latest = trades[0];
		if (latest.sequentialId !== prevTradeRef.current) {
			prevTradeRef.current = latest.sequentialId;
			setFlashPrice({ price: latest.tradePrice, side: latest.askBid });
			const timer = setTimeout(() => setFlashPrice(null), 500);
			return () => clearTimeout(timer);
		}
	}, [trades]);

	const { asks, bids, maxSize, spread, spreadPct } = useMemo(() => {
		if (!orderbook || !orderbook.units.length) {
			return { asks: [], bids: [], maxSize: 0, spread: 0, spreadPct: '' };
		}

		// asks: 오름차순 정렬 (column-reverse로 표시되므로 낮은 가격이 아래/스프레드 근처)
		const askEntries = orderbook.units
			.filter((u) => u.askPrice > 0)
			.map((u) => ({ price: u.askPrice, size: u.askSize }))
			.sort((a, b) => a.price - b.price)
			.slice(0, 15);

		const bidEntries = orderbook.units
			.filter((u) => u.bidPrice > 0)
			.map((u) => ({ price: u.bidPrice, size: u.bidSize }))
			.sort((a, b) => b.price - a.price)
			.slice(0, 15);

		const allSizes = [...askEntries.map((e) => e.size), ...bidEntries.map((e) => e.size)];
		const max = Math.max(...allSizes, 0.0001);

		const sp = askEntries.length > 0 && bidEntries.length > 0
			? askEntries[0].price - bidEntries[0].price
			: 0;

		const midPrice = bidEntries.length > 0 ? bidEntries[0].price : 1;
		const pct = midPrice > 0 ? ((sp / midPrice) * 100).toFixed(2) : '0.00';

		return {
			asks: askEntries, // reverse 제거 — CSS column-reverse로 처리
			bids: bidEntries,
			maxSize: max,
			spread: sp,
			spreadPct: pct,
		};
	}, [orderbook]);

	// 호가 사운드 — 매 업데이트마다 재생 (bitFlyer 스타일 연속 딸깍)
	useEffect(() => {
		if (asks.length === 0 && bids.length === 0) return;

		const currentPrices = new Set<number>();
		asks.forEach((e) => currentPrices.add(e.price));
		bids.forEach((e) => currentPrices.add(e.price));

		const prev = prevPricesRef.current;
		if (prev.size > 0) {
			let hasRemove = false;
			prev.forEach((p) => {
				if (!currentPrices.has(p)) hasRemove = true;
			});

			if (hasRemove) {
				playOrderbookSound('remove');
			} else {
				playOrderbookSound('add');
			}
		}

		prevPricesRef.current = currentPrices;
	}, [asks, bids, playOrderbookSound]);

	// LTP 가이드선이 asks/bids 범위에 있는지 확인
	const ltpInAsks = ltp5mAgo !== null && asks.length > 0 && ltp5mAgo >= asks[0]?.price;
	const ltpInBids = ltp5mAgo !== null && bids.length > 0 && ltp5mAgo <= bids[0]?.price;

	if (!orderbook) {
		return (
			<div className='orderbook'>
				<div className='orderbook-title'>
					<span>호가</span>
				</div>
				<div className='orderbook-loading'>준비 중...</div>
			</div>
		);
	}

	return (
		<div className='orderbook'>
			<div className='orderbook-title'>
				<span>호가</span>
				<span className='orderbook-total'>
					<span className='total-ask'>매도 {formatSize(orderbook.totalAskSize)}</span>
					<span className='total-bid'>매수 {formatSize(orderbook.totalBidSize)}</span>
				</span>
			</div>
			<div className='orderbook-body'>
				{/* 매도 호가 — column-reverse로 낮은 가격이 스프레드 근처 */}
				<div className='ask-section'>
					{asks.map((entry, i) => {
						const isFlash = flashPrice && flashPrice.side === 'ASK' && flashPrice.price === entry.price;
						const isLtp = ltpInAsks && ltp5mAgo === entry.price;
						return (
							<div key={`ask-${i}`} className={`orderbook-row ask ${isFlash ? 'flash-sell' : ''}`}>
								<div className='bar' style={{ width: `${(entry.size / maxSize) * 100}%` }} />
								<span className='size'>{formatSize(entry.size)}</span>
								<span className='price'>{formatPrice(entry.price)}</span>
								{isLtp && <div className='ltp-guide'>LTP 5m ago</div>}
							</div>
						);
					})}
				</div>

				{/* 스프레드 — 항상 중앙 고정 */}
				<div className='spread-row'>
					<span className='spread-price'>{ticker ? formatPrice(ticker.tradePrice) : ''}</span>
					<span className='spread-info'>스프레드 {formatPrice(spread)} ({spreadPct}%)</span>
				</div>

				{/* 매수 호가 */}
				<div className='bid-section'>
					{bids.map((entry, i) => {
						const isFlash = flashPrice && flashPrice.side === 'BID' && flashPrice.price === entry.price;
						const isLtp = ltpInBids && ltp5mAgo === entry.price;
						return (
							<div key={`bid-${i}`} className={`orderbook-row bid ${isFlash ? 'flash-buy' : ''}`}>
								<div className='bar' style={{ width: `${(entry.size / maxSize) * 100}%` }} />
								<span className='price'>{formatPrice(entry.price)}</span>
								<span className='size'>{formatSize(entry.size)}</span>
								{isLtp && <div className='ltp-guide'>LTP 5m ago</div>}
							</div>
						);
					})}
				</div>
			</div>
		</div>
	);
}