'use client';

import { useState, useRef, useEffect, useCallback, useMemo, type CSSProperties, type KeyboardEvent, type ReactNode } from 'react';
import Link from 'next/link';
import { HubConnectionState } from '@microsoft/signalr';
import useAuth from '@/hooks/useAuth';
import { useSignalRContext } from '@/contexts/signalrProvider';
import type { ChatMessage } from '@/types/chat';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUsers, faPaperPlane, faBullhorn, faArrowDown } from '@fortawesome/free-solid-svg-icons';

const ROOM_KEY = 'main';
const MAX_MESSAGES = 200; // 최근 200건 유지·오버플로 드랍 (Backend ChatSettings.MaxMessages 와 동일)
const MAX_SYSTEM_MESSAGES = 50;
const MAX_CONTENT_LENGTH = 500;
const GLOBAL_RATE_LIMIT_SECONDS = 2; // Hub 전역 rate limit (ChatSettings.RateLimitSeconds)
const SCROLL_BOTTOM_THRESHOLD = 50;

type SystemMessage = {
	id: number;
	content: string;
	receivedAt: string;
};

type MergedItem =
	| { kind: 'chat'; time: string; data: ChatMessage }
	| { kind: 'system'; time: string; data: SystemMessage };

type ConnectionState = 'connecting'|'connected'|'reconnecting'|'disconnected';

// 메시지 dedupe 키 — ChatMessage 페이로드에 단일 ID 필드가 없어 (memberSID, sentAt, content) 합성 키 사용
// SSR 초기 히스토리 ↔ JoinRoom ReceiveHistory ↔ 실시간 ReceiveMessage 간 중복 제거
const messageKey = (m: ChatMessage) => `${m.memberSID}|${m.sentAt}|${m.content}`;

const formatTime = (dateStr: string) => {
	const date = new Date(dateStr);
	return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
};

type Props = {
	initialMessages?: ChatMessage[];
	notice?: string|null;
	slowModeSeconds?: number;
	// 헤더 우측(.chat-room__meta)에 주입할 컨트롤 — 채팅 도크의 접기 버튼 등 (없으면 미렌더)
	headerSlot?: ReactNode;
};

export default function MainChat({ initialMessages = [], notice = null, slowModeSeconds = 0, headerSlot }: Props)
{
	const { isAuthenticated } = useAuth();
	const { chatConnection, chatConnected } = useSignalRContext();

	const [messages, setMessages] = useState<ChatMessage[]>(initialMessages);
	const [systemMessages, setSystemMessages] = useState<SystemMessage[]>([]);
	const [participantCount, setParticipantCount] = useState(0);
	const [connState, setConnState] = useState<ConnectionState>('connecting');
	const [kicked, setKicked] = useState(false);
	const [inputValue, setInputValue] = useState('');
	const [cooldownLeft, setCooldownLeft] = useState(0);
	const [showJump, setShowJump] = useState(false);

	const listRef = useRef<HTMLDivElement>(null);
	const autoScrollRef = useRef(true);
	const systemIdRef = useRef(0);
	const cooldownEndRef = useRef(0);
	const activeRef = useRef(true);

	const pushSystem = useCallback((content: string) => {
		setSystemMessages((prev) => {
			const next = [...prev, { id: ++systemIdRef.current, content, receivedAt: new Date().toISOString() }];
			return next.length > MAX_SYSTEM_MESSAGES ? next.slice(next.length - MAX_SYSTEM_MESSAGES) : next;
		});
	}, []);

	const appendMessage = useCallback((message: ChatMessage) => {
		setMessages((prev) => {
			const key = messageKey(message);
			if (prev.some((c) => messageKey(c) === key)) {
				return prev;
			}
			const next = [...prev, message];
			return next.length > MAX_MESSAGES ? next.slice(next.length - MAX_MESSAGES) : next;
		});
	}, []);

	// JoinRoom/재연결 시 ReceiveHistory — SSR 초기분과 병합 (dedupe + 시간순 + 상한)
	const mergeHistory = useCallback((history: ChatMessage[]) => {
		setMessages((prev) => {
			const seen = new Set(prev.map(messageKey));
			const added = history.filter((c) => !seen.has(messageKey(c)));
			if (added.length === 0) {
				return prev;
			}
			const next = [...prev, ...added].sort((a, b) => new Date(a.sentAt).getTime() - new Date(b.sentAt).getTime());
			return next.length > MAX_MESSAGES ? next.slice(next.length - MAX_MESSAGES) : next;
		});
	}, []);

	// ── 연결 라이프사이클: provider 의 chatConnection 재사용, JoinRoom 은 마운트 시 · LeaveRoom 은 언마운트 시 ──
	useEffect(() => {
		if (!chatConnection || !chatConnected) {
			return;
		}

		activeRef.current = true;

		const handleHistory = (history: ChatMessage[]) => mergeHistory(history);
		const handleMessage = (message: ChatMessage) => appendMessage(message);
		const handleSystem = (content: string) => pushSystem(content);
		const handleCount = (count: number) => setParticipantCount(count);
		const handleKick = () => {
			setKicked(true);
			pushSystem('관리자에 의해 채팅 이용이 제한되었습니다.');
		};

		chatConnection.on('ReceiveHistory', handleHistory);
		chatConnection.on('ReceiveMessage', handleMessage);
		chatConnection.on('ReceiveSystemMessage', handleSystem);
		chatConnection.on('ReceiveParticipantCount', handleCount);
		chatConnection.on('Kick', handleKick);

		// 자동 재연결 상태 UX — signalR 은 이 콜백들의 해제 API 가 없어 activeRef 로 stale 호출 가드
		chatConnection.onreconnecting(() => {
			if (activeRef.current) {
				setConnState('reconnecting');
			}
		});
		chatConnection.onreconnected(() => {
			if (!activeRef.current) {
				return;
			}
			setConnState('connected');
			// 재연결 시 그룹 멤버십 소실 → 재참가 (히스토리 재수신은 mergeHistory 가 dedupe)
			chatConnection.invoke('JoinRoom', ROOM_KEY).catch((err) => {
				console.error('채팅 룸 재참가 실패:', err);
			});
		});
		chatConnection.onclose(() => {
			if (activeRef.current) {
				setConnState('disconnected');
			}
		});

		setConnState('connected');
		chatConnection.invoke('JoinRoom', ROOM_KEY).catch((err) => {
			console.error('채팅 룸 참가 실패:', err);
			pushSystem('채팅방 입장에 실패했습니다. 새로고침 후 다시 시도해 주세요.');
		});

		return () => {
			activeRef.current = false;

			chatConnection.off('ReceiveHistory', handleHistory);
			chatConnection.off('ReceiveMessage', handleMessage);
			chatConnection.off('ReceiveSystemMessage', handleSystem);
			chatConnection.off('ReceiveParticipantCount', handleCount);
			chatConnection.off('Kick', handleKick);

			if (chatConnection.state === HubConnectionState.Connected) {
				chatConnection.invoke('LeaveRoom').catch(() => {});
			}
		};
	}, [chatConnection, chatConnected, mergeHistory, appendMessage, pushSystem]);

	// 채팅 + 시스템 메시지 시간순 병합
	const merged = useMemo<MergedItem[]>(() => {
		const items: MergedItem[] = [
			...messages.map((c) => ({ kind: 'chat' as const, time: c.sentAt, data: c })),
			...systemMessages.map((c) => ({ kind: 'system' as const, time: c.receivedAt, data: c }))
		];
		items.sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime());
		return items;
	}, [messages, systemMessages]);

	// 자동 스크롤 (하단 고정) — 위로 스크롤 중이면 "새 메시지 ↓" 점프 버튼 노출
	useEffect(() => {
		const el = listRef.current;
		if (!el || merged.length === 0) {
			return;
		}
		if (autoScrollRef.current) {
			el.scrollTop = el.scrollHeight;
		} else {
			setShowJump(true);
		}
	}, [merged.length]);

	const handleScroll = useCallback(() => {
		const el = listRef.current;
		if (!el) {
			return;
		}
		const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - SCROLL_BOTTOM_THRESHOLD;
		autoScrollRef.current = atBottom;
		if (atBottom) {
			setShowJump(false);
		}
	}, []);

	const jumpToBottom = useCallback(() => {
		const el = listRef.current;
		if (!el) {
			return;
		}
		el.scrollTop = el.scrollHeight;
		autoScrollRef.current = true;
		setShowJump(false);
	}, []);

	// 전송 쿨다운 (전역 2초 + 룸 SlowMode 중 큰 값) — 남은 초 표시
	const cooling = cooldownLeft > 0;
	useEffect(() => {
		if (!cooling) {
			return;
		}
		const timer = window.setInterval(() => {
			const left = Math.ceil((cooldownEndRef.current - Date.now()) / 1000);
			setCooldownLeft(left > 0 ? left : 0);
		}, 250);
		return () => window.clearInterval(timer);
	}, [cooling]);

	const handleSend = useCallback(async () => {
		const trimmed = inputValue.trim();
		if (!trimmed || trimmed.length > MAX_CONTENT_LENGTH || cooldownLeft > 0 || kicked) {
			return;
		}
		if (!chatConnection || chatConnection.state !== HubConnectionState.Connected) {
			return;
		}

		try {
			await chatConnection.invoke('SendMessage', trimmed);
			setInputValue('');

			const seconds = Math.max(GLOBAL_RATE_LIMIT_SECONDS, slowModeSeconds);
			cooldownEndRef.current = Date.now() + seconds * 1000;
			setCooldownLeft(seconds);
		} catch (error) {
			console.error('메시지 전송 실패:', error);
			pushSystem('메시지 전송에 실패했습니다. 잠시 후 다시 시도해 주세요.');
		}
	}, [inputValue, cooldownLeft, kicked, chatConnection, slowModeSeconds, pushSystem]);

	const handleKeyDown = useCallback((e: KeyboardEvent<HTMLInputElement>) => {
		if (e.key === 'Enter' && !e.nativeEvent.isComposing) {
			e.preventDefault();
			handleSend();
		}
	}, [handleSend]);

	const canType = connState === 'connected' && !kicked;
	const canSend = canType && inputValue.trim().length > 0 && cooldownLeft === 0;

	return (
		<div id='chat-room'>
			{/* 헤더: 제목 + 접속자 수 + 연결 상태 */}
			<header className='chat-room__head'>
				<h1>실시간 채팅</h1>
				<div className='chat-room__meta'>
					<span className='chat-room__count' aria-live='polite'>
						<FontAwesomeIcon icon={faUsers} />
						<span>{participantCount.toLocaleString()}명 참여 중</span>
					</span>
					{connState === 'connecting' && (
						<span className='chat-room__state'>연결 중…</span>
					)}
					{connState === 'reconnecting' && (
						<span className='chat-room__state chat-room__state--warn' role='status'>재연결 중…</span>
					)}
					{connState === 'disconnected' && (
						<span className='chat-room__state chat-room__state--error' role='status'>연결 끊김 — 새로고침 후 다시 시도해 주세요</span>
					)}
					{headerSlot}
				</div>
			</header>

			{/* 상단 공지 */}
			{notice && (
				<div className='chat-room__notice' role='note'>
					<FontAwesomeIcon icon={faBullhorn} />
					<span>{notice}</span>
				</div>
			)}

			{/* 메시지 리스트 */}
			<div className='chat-room__body'>
				<div className='chat-room__messages' ref={listRef} onScroll={handleScroll} aria-live='off'>
					{merged.length === 0 && (
						<div className='chat-room__empty'>아직 메시지가 없습니다. 첫 메시지를 남겨보세요.</div>
					)}
					{merged.map((item) => {
						if (item.kind === 'system') {
							return (
								<div key={`sys-${item.data.id}`} className='chat-room__system'>
									{item.data.content}
								</div>
							);
						}

						const msg = item.data;
						const badgeUrl = msg.titleIconUrl || msg.gradeImageUrl || msg.memberIcon;
						const badgeAlt = msg.titleName ?? '';
						return (
							<div key={messageKey(msg)} className='chat-room__message'>
								<time className='chat-room__time' dateTime={msg.sentAt}>{formatTime(msg.sentAt)}</time>
								{badgeUrl && (
									<img src={badgeUrl} alt={badgeAlt} className='chat-room__badge' aria-hidden={!badgeAlt} />
								)}
								<span
									className='chat-room__name'
									style={msg.titleColor ? ({ '--title-color': msg.titleColor } as CSSProperties) : undefined}
								>
									{msg.memberName || msg.memberSID}
								</span>
								<span className='chat-room__content'>{msg.content}</span>
							</div>
						);
					})}
				</div>

				{showJump && (
					<button type='button' className='chat-room__jump' onClick={jumpToBottom}>
						<FontAwesomeIcon icon={faArrowDown} />
						<span>새 메시지</span>
					</button>
				)}
			</div>

			{/* 입력부 — 게스트는 읽기 전용 + 로그인 CTA */}
			<div className='chat-room__footer'>
				{kicked ? (
					<div className='chat-room__blocked' role='status'>
						관리자에 의해 채팅 이용이 제한되었습니다.
					</div>
				) : isAuthenticated ? (
					<>
						<div className='chat-room__input-row'>
							<input
								type='text'
								placeholder='메시지를 입력하세요'
								value={inputValue}
								onChange={(e) => setInputValue(e.target.value)}
								onKeyDown={handleKeyDown}
								maxLength={MAX_CONTENT_LENGTH}
								disabled={!canType}
								aria-label='채팅 메시지 입력'
							/>
							<button type='button' title='전송' onClick={handleSend} disabled={!canSend}>
								{cooldownLeft > 0 ? (
									<span className='chat-room__cooldown'>{cooldownLeft}</span>
								) : (
									<FontAwesomeIcon icon={faPaperPlane} />
								)}
							</button>
						</div>
						<div className='chat-room__input-meta'>
							{slowModeSeconds > GLOBAL_RATE_LIMIT_SECONDS && (
								<span className='chat-room__slowmode'>슬로우 모드 {slowModeSeconds}초</span>
							)}
							{cooldownLeft > 0 && (
								<span className='chat-room__cooldown-left' aria-live='polite'>{cooldownLeft}초 후 전송 가능</span>
							)}
							<span className='chat-room__counter'>{inputValue.length}/{MAX_CONTENT_LENGTH}</span>
						</div>
					</>
				) : (
					<div className='chat-room__guest'>
						<span>읽기는 자유롭게, 참여는 로그인 후 가능합니다.</span>
						<Link href='/login' className='chat-room__login-cta'>로그인 후 참여</Link>
					</div>
				)}
			</div>
		</div>
	);
}