import { useState, useEffect, useCallback, useRef } from 'react';
import { doc, onSnapshot, runTransaction, Timestamp, DocumentSnapshot } from 'firebase/firestore';
import { db } from '@/lib/firebase';
import { useAuth } from '@/contexts/AuthContext';
import { Document, COLLECTIONS } from '@/types/firestore';

const LOCK_TIMEOUT_MS = 5 * 60 * 1000; // 5분 (이 시간 동안 갱신 없으면 다른 사람이 뺏을 수 있음)
const HEARTBEAT_INTERVAL_MS = 1 * 60 * 1000; // 1분마다 갱신

export function useDocumentLock(docId: string) {
    const { user } = useAuth();
    const [lockInfo, setLockInfo] = useState<{
        isLocked: boolean;
        lockedBy: string | null;
        lockedByName: string | null;
        mine: boolean;
    }>({
        isLocked: false,
        lockedBy: null,
        lockedByName: null,
        mine: false,
    });

    const heartbeatRef = useRef<NodeJS.Timeout | null>(null);

    // 잠금 상태 구독
    useEffect(() => {
        if (!docId) return;

        const unsubscribe = onSnapshot(doc(db, COLLECTIONS.DOCUMENTS, docId), (snapshot) => {
            if (!snapshot.exists()) return;

            const data = snapshot.data() as Document;
            const now = Date.now();
            const editingAt = data.editingAt?.toMillis() || 0;
            const isExpired = now - editingAt > LOCK_TIMEOUT_MS;

            if (data.editingBy && !isExpired) {
                setLockInfo({
                    isLocked: true,
                    lockedBy: data.editingBy,
                    lockedByName: data.editingByName || 'Unknown User',
                    mine: user?.uid === data.editingBy,
                });
            } else {
                setLockInfo({
                    isLocked: false,
                    lockedBy: null,
                    lockedByName: null,
                    mine: false,
                });
            }
        });

        return () => unsubscribe();
    }, [docId, user?.uid]);

    // 잠금 획득 시도
    const acquireLock = useCallback(async () => {
        if (!user || !docId) return false;

        try {
            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, 'documents', docId);
                const docSnap = await transaction.get(docRef);

                if (!docSnap.exists()) {
                    // 문서가 없으면(새 문서) 잠금 없이 편집 허용
                    return;
                }

                const data = docSnap.data() as Document;
                const now = Date.now();
                const editingAt = data.editingAt?.toMillis() || 0;

                // 이미 다른 사람이 잠그고 있고, 아직 만료되지 않았다면 실패
                if (data.editingBy && data.editingBy !== user.uid && (now - editingAt < LOCK_TIMEOUT_MS)) {
                    throw new Error("ALREADY_LOCKED");
                }

                transaction.update(docRef, {
                    editingBy: user.uid,
                    editingByName: user.displayName || user.email?.split('@')[0] || 'Anonymous',
                    editingAt: Timestamp.now(),
                });
            });
            return true;
        } catch (e: unknown) {
            console.error("Failed to acquire lock:", e);
            if (e instanceof Error && e.message === "ALREADY_LOCKED") {
                return false;
            }
            throw e; // 다른 에러는 throw
        }
    }, [docId, user]);

    // 잠금 해제
    const releaseLock = useCallback(async () => {
        if (!user || !docId) return;

        try {
            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, 'documents', docId);
                const docSnap = await transaction.get(docRef);

                if (!docSnap.exists()) return;

                const data = docSnap.data() as Document;

                // 내 잠금일 때만 해제
                if (data.editingBy === user.uid) {
                    transaction.update(docRef, {
                        editingBy: null,
                        editingByName: null,
                        editingAt: null
                    });
                }
            });
            // 해제 성공 후 하트비트 중지
            if (heartbeatRef.current) {
                clearInterval(heartbeatRef.current);
                heartbeatRef.current = null;
            }
        } catch (e) {
            console.error("Failed to release lock:", e);
        }
    }, [docId, user]);

    // 잠금 갱신 (Heartbeat)
    const renewLock = useCallback(async () => {
        if (!user || !docId) return;

        try {
            // updateDoc만 사용 (트랜잭션 굳이 필요 없음, 내 잠금 확인은 어렵지만 update 전제조건으로) 
            // 안전하게 하려면 transaction이 맞지만 성능 위해
            // 일단 간단히 updateDoc (Firestore 규칙이 있다면 '내 잠금일 때만 update 허용' 해야함. 지금 규칙은 없으므로..)
            // 여기선 안전하게 transaction 사용
            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, 'documents', docId);
                const docSnap = await transaction.get(docRef);
                if (!docSnap.exists()) return;
                const data = docSnap.data() as Document;

                if (data.editingBy === user.uid) {
                    transaction.update(docRef, {
                        editingAt: Timestamp.now()
                    });
                } else {
                    // 내 잠금이 아니면 하트비트 중단
                    if (heartbeatRef.current) {
                        clearInterval(heartbeatRef.current);
                        heartbeatRef.current = null;
                    }
                }
            });
        } catch (e) {
            console.error("Failed to renew lock:", e);
        }
    }, [docId, user]);

    // 편집 시작 시 하트비트 시작
    const startHeartbeat = useCallback(() => {
        if (heartbeatRef.current) clearInterval(heartbeatRef.current);
        heartbeatRef.current = setInterval(renewLock, HEARTBEAT_INTERVAL_MS);
    }, [renewLock]);

    const stopHeartbeat = useCallback(() => {
        if (heartbeatRef.current) {
            clearInterval(heartbeatRef.current);
            heartbeatRef.current = null;
        }
    }, []);

    // 언마운트 시 잠금 해제 시도 (useEffect cleanup)
    useEffect(() => {
        return () => {
            if (lockInfo.mine) {
                releaseLock(); // 비동기라 cleanup에서 완벽히 보장되진 않으나 최선을 다해 해제
            }
            if (heartbeatRef.current) {
                clearInterval(heartbeatRef.current);
            }
        };
    }, [lockInfo.mine, releaseLock]);

    return {
        lockInfo,
        acquireLock,
        releaseLock,
        startHeartbeat,
        stopHeartbeat
    };
}
