'use client';

import './style.scss';
import { useEffect, useState, useCallback } from 'react';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSun, faMoon, faGlobe, faBookmark, faAnglesLeft, faAnglesRight, faEllipsis } from '@fortawesome/free-solid-svg-icons';
import { useSignalRContext } from '@/contexts/signalrProvider';
import { ChannelListItem, ChannelStatusUpdate } from '@/types/channel';
import { buildChannelUrl, buildWatchUrl, formatHandle } from '@/lib/utils/channel';
import useTheme from '@/hooks/useTheme';

const STORAGE_KEY = 'dpot-sidebar-collapsed';
const PAGE_SIZE = 10;
const WIDTH_EXPANDED = '220px';
const WIDTH_COLLAPSED = '64px';
const THUMB_PLACEHOLDER = '/resources/no-image.png';

// 뷰포트 높이 기반 최초 표시 채널 수 계산용 상수
// 채널 아이템 1개 ≒ padding 10px*2 + thumb 36px = 56px
// 헤더(약 60) + 푸터(약 70) + "더 보기" 버튼(약 46) ≒ 180px 예약
const ITEM_HEIGHT_PX = 56;
const RESERVED_HEIGHT_PX = 180;

function computeInitialVisible(): number
{
	if (typeof window === 'undefined') {
		return PAGE_SIZE;
	}
	const available = window.innerHeight - RESERVED_HEIGHT_PX;
	const fit = Math.floor(available / ITEM_HEIGHT_PX);
	return Math.max(PAGE_SIZE, fit);
}

type Props = {
	initialChannels?: ChannelListItem[];
};

export default function ChannelSidebar({ initialChannels }: Props)
{
	const sortChannels = useCallback((list: ChannelListItem[]) => {
		return [...list].sort((a, b) => {
			if (a.isLive && !b.isLive) {
				return -1;
			}

			if (!a.isLive && b.isLive) {
				return 1;
			}

			if (a.isLive && b.isLive) {
				return b.viewerCount - a.viewerCount;
			}

			// 비라이브: 서버가 반환한 random 순서 유지 (_offlineRank 는 로드 시점 index 부여)
			return (a._offlineRank ?? 0) - (b._offlineRank ?? 0);
		});
	}, []);

	const [channels, setChannels] = useState<ChannelListItem[]>(() => sortChannels(initialChannels ?? []));
	const [langOpen, setLangOpen] = useState(false);
	const [collapsed, setCollapsed] = useState(false);
	const [visibleCount, setVisibleCount] = useState<number>(PAGE_SIZE);
	const router = useRouter();
	// ChannelStatusBroadcaster 는 AppHub 의 channel:{sid} 그룹으로 송출하므로 appConnection 사용 필수.
	// (ChatHub 를 쓰면 그룹 키(chat:channel:{sid}) 불일치로 ReceiveChannelStatus 가 영영 안 옴 + 채팅 입장 메시지 도배)
	const { appConnection } = useSignalRContext();
	const { toggleTheme, isDark } = useTheme();

	// 최초 mount 시 localStorage에서 collapsed 상태 복원
	useEffect(() => {
		try {
			const saved = window.localStorage.getItem(STORAGE_KEY);
			if (saved === 'true') {
				setCollapsed(true);
			}
		} catch {}
	}, []);

	// 뷰포트 높이에 따라 최초 표시 채널 수 계산 — 4K/8K 등 세로가 긴 화면에서 더 많은 채널을 한번에 표시
	// 사용자가 "더 보기" 를 눌러 늘려놓은 경우 줄어들지 않도록 max 로 갱신
	useEffect(() => {
		const apply = () => {
			const next = computeInitialVisible();
			setVisibleCount(prev => Math.max(prev, next));
		};
		apply();
		window.addEventListener('resize', apply);
		return () => {
			window.removeEventListener('resize', apply);
		};
	}, []);

	// collapsed 변경 시 html 루트의 CSS variable + 클래스 동기화 (layout grid가 반응)
	useEffect(() => {
		const root = document.documentElement;
		root.style.setProperty('--dpot-sidebar-width', collapsed ? WIDTH_COLLAPSED : WIDTH_EXPANDED);
		root.classList.toggle('dpot-sidebar-collapsed', collapsed);
		try {
			window.localStorage.setItem(STORAGE_KEY, String(collapsed));
		} catch {}
		return () => {
			// unmount 시 원복 (전체 앱 재사용성 보장)
			root.style.removeProperty('--dpot-sidebar-width');
			root.classList.remove('dpot-sidebar-collapsed');
		};
	}, [collapsed]);

	// SignalR: 채널 상태 실시간 업데이트 (AppHub.ReceiveChannelStatus)
	useEffect(() => {
		if (!appConnection) {
			return;
		}

		const handler = (status: ChannelStatusUpdate) => {
			setChannels(prev => {
				const updated = prev.map(ch =>
					ch.channelSID === status.channelSID ? { ...ch, isLive: status.isLive, viewerCount: status.viewerCount, videoId: status.videoId } : ch
				);
				return sortChannels(updated);
			});
		};

		appConnection.on('ReceiveChannelStatus', handler);
		return () => {
			appConnection.off('ReceiveChannelStatus', handler);
		};
	}, [appConnection, sortChannels]);

	// ChannelStatusBroadcaster 가 AppHub 의 Clients.Group("channel:{sid}") 로 송출 → AppHub.JoinChannel 로 그룹 가입.
	// AppHub.JoinChannel 은 순수 그룹 가입만 수행 (사이드이펙트 없음).
	// SID 목록 변경 또는 재연결 시 다시 가입.
	const channelSidsKey = channels.map(c => c.channelSID).join(',');
	useEffect(() => {
		if (!appConnection) {
			return;
		}

		const sids = channelSidsKey ? channelSidsKey.split(',') : [];
		if (sids.length === 0) {
			return;
		}

		const joinAll = async () => {
			if (appConnection.state !== 'Connected') {
				return;
			}
			for (const sid of sids) {
				try {
					await appConnection.invoke('JoinChannel', sid);
				} catch (err) {
					console.warn('[ChannelSidebar] JoinChannel 실패:', sid, err);
				}
			}
		};

		joinAll();
		appConnection.onreconnected(joinAll);

		return () => {
			if (appConnection.state !== 'Connected') {
				return;
			}
			for (const sid of sids) {
				appConnection.invoke('LeaveChannel', sid).catch(() => {});
			}
		};
	}, [appConnection, channelSidsKey]);

	const handleClick = (ch: ChannelListItem) => {
		if (ch.isLive && ch.videoId) {
			router.push(buildWatchUrl(ch));
		} else {
			router.push(buildChannelUrl(ch));
		}
	};

	const formatCount = (n: number) => {
		if (n >= 10000) {
			return `${(n / 10000).toFixed(1)}만`;
		}
		if (n >= 1000) {
			return `${(n / 1000).toFixed(1)}K`;
		}
		return n.toString();
	};

	const getThumbnailUrl = (ch: ChannelListItem) => {
		if (ch.thumbnailUrl) {
			return ch.thumbnailUrl;
		}
		// YouTube 채널 ID 를 `/a/` 경로에 끼워넣은 fallback 은 항상 400 (해당 path 는 Google 계정 아바타 토큰용)
		// → 로컬 placeholder 로 안전 대체. 실제 채널 썸네일은 YouTube Data API 동기화로 채워야 함.
		return THUMB_PLACEHOLDER;
	};

	const handleToggleCollapse = useCallback(() => {
		setCollapsed(prev => !prev);
		setLangOpen(false);
	}, []);

	const handleShowMore = useCallback(() => {
		setVisibleCount(prev => prev + PAGE_SIZE);
	}, []);

	const visibleChannels = channels.slice(0, visibleCount);
	const hasMore = channels.length > visibleCount;

	return (
		<div className={`channel-sidebar${collapsed ? ' channel-sidebar--collapsed' : ''}`}>
			{/* 헤더 */}
			<div className="channel-sidebar__header">
				{!collapsed && <span className="channel-sidebar__header-title">생방송 채널</span>}
				<button
					type="button"
					className="channel-sidebar__collapse-btn"
					onClick={handleToggleCollapse}
					aria-label={collapsed ? '사이드바 펼치기' : '사이드바 접기'}
					aria-expanded={!collapsed}
					title={collapsed ? '사이드바 펼치기' : '사이드바 접기'}
				>
					<FontAwesomeIcon icon={collapsed ? faAnglesRight : faAnglesLeft} />
				</button>
			</div>

			{/* 채널 목록 */}
			<div className="channel-sidebar__list">
				{channels.length === 0 && !collapsed && (
					<div className="channel-sidebar__empty">등록된 채널이 없습니다</div>
				)}
				{visibleChannels.map(ch => (
					<div
						key={ch.channelSID}
						className={`channel-sidebar__item${ch.isLive ? ' channel-sidebar__item--live' : ''}`}
						onClick={() => handleClick(ch)}
						role="button"
						tabIndex={0}
						aria-label={`${ch.name}${ch.isLive ? ` · 시청자 ${formatCount(ch.viewerCount)}` : ''}`}
						onKeyDown={(e) => {
							if (e.key === 'Enter' || e.key === ' ') {
								e.preventDefault();
								handleClick(ch);
							}
						}}
						title={collapsed ? `${ch.name}${ch.isLive ? ` · 시청자 ${formatCount(ch.viewerCount)}` : ''}` : undefined}
					>
						<div className="channel-sidebar__thumb">
							<Image src={getThumbnailUrl(ch)} alt={ch.name} width={36} height={36} unoptimized />
							{collapsed && ch.isLive && <span className="channel-sidebar__thumb-dot" aria-hidden="true" />}
						</div>
						{!collapsed && (
							<>
								<div className="channel-sidebar__info">
									<div className="channel-sidebar__name">{ch.name}</div>
									<div className="channel-sidebar__sub">
										{ch.subscriberCount > 0 ? `구독자 ${formatCount(ch.subscriberCount)}` : (ch.handle ? formatHandle(ch.handle) : '')}
									</div>
								</div>
								<div className="channel-sidebar__status">
									{ch.isLive && (
										<span className="channel-sidebar__viewers">{formatCount(ch.viewerCount)}</span>
									)}
									<span className={`channel-sidebar__led${ch.isLive ? ' channel-sidebar__led--on' : ''}`} />
								</div>
							</>
						)}
					</div>
				))}

				{/* 더 보기 */}
				{hasMore && (
					<button
						type="button"
						className="channel-sidebar__more"
						onClick={handleShowMore}
						aria-label={`채널 ${PAGE_SIZE}개 더 보기`}
						title={collapsed ? '더 보기' : undefined}
					>
						{collapsed ? <FontAwesomeIcon icon={faEllipsis} /> : <span>더 보기</span>}
					</button>
				)}
			</div>

			{/* 하단: 다크모드 / 다국어 / 즐겨찾기 */}
			<div className="channel-sidebar__footer">
				{langOpen && !collapsed && (
					<div className="channel-sidebar__lang-dropdown">
						<button type="button" className="channel-sidebar__lang-option channel-sidebar__lang-option--active" onClick={() => setLangOpen(false)}>한국어</button>
						<button type="button" className="channel-sidebar__lang-option" onClick={() => setLangOpen(false)}>English</button>
					</div>
				)}
				<div className="channel-sidebar__footer-actions">
					<button type="button" className="channel-sidebar__icon-btn" onClick={toggleTheme} aria-label={isDark ? '라이트 모드' : '다크 모드'} title={isDark ? '라이트 모드' : '다크 모드'}>
						<FontAwesomeIcon icon={isDark ? faSun : faMoon} />
					</button>
					<button type="button" className="channel-sidebar__icon-btn" onClick={() => setLangOpen(prev => !prev)} aria-label="다국어" title="다국어">
						<FontAwesomeIcon icon={faGlobe} />
					</button>
					<button type="button" className="channel-sidebar__icon-btn" onClick={() => alert('Ctrl+D (Mac: ⌘+D)를 누르면 사이트를 즐겨찾기에 추가할 수 있습니다.')} aria-label="즐겨찾기" title="즐겨찾기">
						<FontAwesomeIcon icon={faBookmark} />
					</button>
				</div>
			</div>
		</div>
	);
}