'use client';
import { useState, useEffect } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useAuth } from '@/contexts/AuthContext';
import { doc, serverTimestamp, onSnapshot, runTransaction, writeBatch, collection, query, where, getDocs, deleteDoc, arrayUnion, orderBy, limit, addDoc, updateDoc } from 'firebase/firestore';
import { useDocumentLock } from '@/hooks/useDocumentLock';
import { useDraftAutoSave } from '@/hooks/useDraftAutoSave';
import { toast } from 'sonner';
import { confirmDialog } from '@/lib/confirm';
import { useWikiMapContext } from '@/contexts/WikiMapContext';
import { db } from '@/lib/firebase';
import { COLLECTIONS, Document as WikiDocument, DocumentCategory, Visibility } from '@/types/firestore';
import { extractWikiLinks, tokenizeContent } from '@/lib/markdown';
import { formatDurationKorean } from '@/hooks/useAudioRecorder';
import { useVoiceCommandContext } from '@/contexts/VoiceCommandContext';
import { detectNextNumbering, extractCoverImageId } from '@/lib/utils/documentHelpers';
import { ADMIN_EMAILS, formatAuthorName } from '@/lib/constants';

// 카테고리 옵션 정의
export const CATEGORY_OPTIONS: { value: DocumentCategory; label: string; icon: string }[] = [
    { value: 'general', label: '전체 (미분류)', icon: '🔍' },
    { value: 'medical', label: '의료', icon: '🏥' },
    { value: 'casualty', label: '손해', icon: '🚗' },
    { value: 'wealth', label: '자산', icon: '💰' },
    { value: 'practice', label: '실무', icon: '⚖️' },
];

interface RevisionRecord {
    id: string;
    content: string;
    title: string;
    authorId: string;
    authorName: string;
    createdAt: { toDate: () => Date } | null;
    version?: number;
    isRestored?: boolean;
}

export function useDocumentState(docId: string) {
    const { user, userRole, customName, loading } = useAuth();
    const router = useRouter();
    const searchParams = useSearchParams();

    const { wikiMap } = useWikiMapContext();
    const [document, setDocument] = useState<WikiDocument | null>(null);
    const [isEditing, setIsEditing] = useState(false);
    const [editContent, setEditContent] = useState('');
    const [editTitle, setEditTitle] = useState('');
    const [editCategory, setEditCategory] = useState<DocumentCategory>('general');
    const [isSaving, setIsSaving] = useState(false);
    const [loadingDoc, setLoadingDoc] = useState(true);
    const [isTocOpen, setIsTocOpen] = useState(false);
    const [isHistoryModalOpen, setIsHistoryModalOpen] = useState(false);
    const [isUploading, setIsUploading] = useState(false);
    const [isConsentModalOpen, setIsConsentModalOpen] = useState(false);
    const [revisions, setRevisions] = useState<RevisionRecord[]>([]);

    const docType = (document?.id.startsWith('new-') || document?.id.startsWith('daily-'))
        ? (document?.docType || (editTitle.match(/^\d{4}-\d{2}-\d{2}$/) ? 'daily' : 'wiki'))
        : (document?.docType || (document?.title.match(/^\d{4}-\d{2}-\d{2}$/) ? 'daily' : 'wiki'));
    const isDaily = docType === 'daily';

    const [shadowedDocId, setShadowedDocId] = useState<string | null>(null);
    const { lockInfo, acquireLock, releaseLock, startHeartbeat, stopHeartbeat } = useDocumentLock(docId);

    // 자동 임시저장
    const autoSave = useDraftAutoSave({
        docId,
        userId: user?.uid,
        isEditing,
        editContent,
        editTitle,
        editCategory,
    });

    const [isLeaveConfirmOpen, setIsLeaveConfirmOpen] = useState(false);
    const [isDraftRecoveryOpen, setIsDraftRecoveryOpen] = useState(false);

    // 헤더 상태 결정: Daily -> daily, Private -> my, Public -> wiki
    const headerVariant = (isDaily ? 'daily' : (document?.visibility === 'private' ? 'my' : 'wiki')) as 'daily' | 'my' | 'wiki';

    const isAdmin = !!(user?.email && ADMIN_EMAILS.includes(user.email));
    const buttonClass = isDaily ? 'bg-emerald-600 hover:bg-emerald-700 border-emerald-500' : 'bg-indigo-600 hover:bg-indigo-700 border-indigo-500';
    const badgeClass = isDaily ? 'bg-emerald-50 text-emerald-600 border-emerald-100' : 'bg-indigo-50 text-indigo-600 border-indigo-100';

    // Shadow Detection Logic: Check if privacy shadows a public doc
    useEffect(() => {
        const checkShadowing = async () => {
            if (!document || document.visibility !== 'private' || isDaily) {
                setShadowedDocId(null);
                return;
            }

            // Query for a public document with the same title
            const docsRef = collection(db, COLLECTIONS.DOCUMENTS);
            const q = query(
                docsRef,
                where('title', '==', document.title),
                where('visibility', '==', 'public')
            );

            try {
                const querySnapshot = await getDocs(q);

                // 삭제된 문서(isDeleted === true)를 제외하고 첫 번째 유효한 공개 문서를 찾음
                const activePublicDoc = querySnapshot.docs.find(doc => {
                    return doc.data().isDeleted !== true && doc.id !== document.id;
                });

                if (activePublicDoc) {
                    setShadowedDocId(activePublicDoc.id);
                } else {
                    setShadowedDocId(null);
                }
            } catch (error) {
                console.error("Error checking for shadowed documents:", error);
            }
        };

        checkShadowing();
    }, [document, isDaily]);

    // [WikiLink Stale ID Fix] 삭제된 문서 접근 시 동일 제목의 살아있는 문서로 자동 리다이렉트
    useEffect(() => {
        if (!document || !wikiMap || wikiMap.size === 0) return;
        if (!document.isDeleted) return;

        const title = document.title?.trim();
        if (!title) return;

        // wikiMap에서 동일 제목으로 살아있는 문서 탐색
        const redirectId = wikiMap.get(title);
        if (redirectId && redirectId !== docId) {
            router.replace(`/docs/${redirectId}`);
        }
    }, [document, wikiMap, docId, router]);

    // [New] 수정 히스토리 가져오기
    useEffect(() => {
        if (!docId || !document || isEditing || document.id.startsWith('new-')) return;

        const fetchRevisions = async () => {
            try {
                const revisionsRef = collection(db, COLLECTIONS.DOCUMENTS, docId, COLLECTIONS.REVISIONS);
                const q = query(revisionsRef, orderBy('createdAt', 'desc'), limit(20));
                const snapshot = await getDocs(q);

                const docs = snapshot.docs.map(doc => ({
                    id: doc.id,
                    ...doc.data()
                })) as RevisionRecord[];
                setRevisions(docs);
            } catch (error) {
                console.error("Error fetching revisions for history:", error);
            }
        };

        fetchRevisions();
    }, [docId, document?.updatedAt, isEditing]);

    // 문서 데이터 구독 (실시간 업데이트)
    // [Performance Fix] Split into two effects to prevent infinite loop
    useEffect(() => {
        if (!docId || loading) return; // Wait for Auth to initialize

        const docRef = doc(db, COLLECTIONS.DOCUMENTS, docId);

        const unsubscribe = onSnapshot(docRef, (docSnap) => {
            if (docSnap.exists()) {
                const data = docSnap.data() as WikiDocument;
                setDocument({ ...data, id: docSnap.id });
            } else if (docId.startsWith('new-') || docId.startsWith('daily-')) {
                // 유령 문서 (Phantom Documents) 처리
                // daily-YYYY-MM-DD-UID 형식인 경우, 날짜만 제목으로 추출
                let phantomTitle = docId;
                let defaultVisibility: Visibility = 'public';
                let defaultDocType = 'wiki';

                // Check query param for default visibility (from URL, not state to avoid dependency)
                const urlParams = new URLSearchParams(window.location.search);
                const visibilityParam = urlParams.get('visibility');

                if (docId.startsWith('new-')) {
                    phantomTitle = decodeURIComponent(docId.replace(/^new-/, ''));
                    if (visibilityParam === 'private') {
                        defaultVisibility = 'private';
                    }
                } else if (docId.startsWith('daily-')) {
                    // Extract date from daily-YYYY-MM-DD-UID
                    const match = docId.match(/^daily-(\d{4}-\d{2}-\d{2})/);
                    phantomTitle = match ? match[1] : docId;
                    defaultVisibility = 'private'; // Daily notes are private by default
                    defaultDocType = 'daily';
                }

                // Create phantom doc object
                const phantomDoc = {
                    id: docId,
                    title: phantomTitle,
                    content: '',
                    authorId: '',
                    authorName: 'System',
                    visibility: defaultVisibility,
                    docType: defaultDocType as 'wiki' | 'daily',
                    category: defaultDocType === 'wiki' ? 'general' : undefined,
                    properties: {},
                    searchKeywords: [],
                    version: 0,
                    createdAt: new Date() as any,
                    updatedAt: new Date() as any
                } as WikiDocument;

                setDocument(phantomDoc);
            } else {
                toast.error("존재하지 않는 문서입니다.");
                router.push('/');
            }
            setLoadingDoc(false);
        }, (error) => {
            console.error("문서 로딩 에러:", error);
            setLoadingDoc(false);
        });

        return () => unsubscribe();
    }, [docId, router, user, loading]); // Add user/loading dependencies to ensure auth is ready

    // [Performance Fix] Sync local edit state when document changes (external updates)
    useEffect(() => {
        if (document && !isEditing) {
            setEditTitle(document.title);
            setEditContent(document.content);
            setEditCategory(document.category || 'general');
        }
    }, [document, isEditing]);

    // 임시저장본 존재 시 복구 모달 자동 표시
    useEffect(() => {
        if (isEditing && autoSave.hasDraft && autoSave.draftData) {
            setIsDraftRecoveryOpen(true);
        }
    }, [isEditing, autoSave.hasDraft, autoSave.draftData]);

    // 편집 시작 핸들러
    const handleEditClick = async () => {
        if (lockInfo.isLocked && !lockInfo.mine) {
            toast.error(`${lockInfo.lockedByName}님이 편집 중입니다.`);
            return;
        }

        const success = await acquireLock();
        if (success) {
            setIsEditing(true);
            startHeartbeat();
            // 편집 시작 시 임시저장본 확인
            await autoSave.checkForDraft();
        } else {
            toast.error('현재 문서를 편집할 수 없습니다 (잠금 획득 실패).');
        }
    };

    // 편집 취소 핸들러
    const handleCancelClick = async () => {
        // 변경사항이 있으면 이탈 확인 모달 표시
        if (editContent !== document?.content || editTitle !== document?.title) {
            setIsLeaveConfirmOpen(true);
            return;
        }
        // 변경사항이 없으면 바로 편집 종료
        setIsEditing(false);
        if (document) {
            setEditContent(document.content);
            setEditTitle(document.title);
            setEditCategory(document.category || 'general');
        }
        stopHeartbeat();
        await releaseLock();
        // 모바일 사파리 등에서 뒤로가기 시 잠금 해제가 안될 수 있으므로 명시적 해제
    };

    const handleDraftRecover = () => {
        const restored = autoSave.restoreDraft();
        if (restored) {
            setEditContent(restored.content);
            setEditTitle(restored.title);
            if (restored.category) setEditCategory(restored.category as DocumentCategory);
        }
        setIsDraftRecoveryOpen(false);
    };

    const handleDraftDiscard = async () => {
        await autoSave.clearDraft();
        setIsDraftRecoveryOpen(false);
    };

    const handleSave = async (overridingContent?: string, isRestore: boolean = false) => {
        if (!user || !document) return;
        setIsSaving(true);
        try {
            const finalContent = overridingContent !== undefined ? overridingContent : editContent;

            // Extract outgoing links (titles) and IDs for backlink functionality
            let titles, ids;
            try {
                const result = extractWikiLinks(finalContent);
                titles = result.titles;
                ids = result.ids;
            } catch (linkError) {
                console.error('[SAVE DEBUG] Link extraction failed:', linkError);
                throw new Error('Link extraction failed');
            }

            // Tokenize content for unlinked mentions
            const searchKeywords = tokenizeContent(finalContent);
            // Daily Note ID pattern check for legacy or title-based inference
            const inferredType = (docId.startsWith('daily-') || editTitle.match(/^\d{4}-\d{2}-\d{2}$/)) ? 'daily' : 'wiki';

            // 카테고리 필수 선택 체크 (Wiki인 경우)
            if (inferredType === 'wiki' && editCategory === 'general') {
                toast.error('카테고리를 선택해주세요. (미분류로는 저장할 수 없습니다)');
                setIsSaving(false);
                return;
            }

            // [Phase 5 Fix] 중복 위키 제목 방지 (Daily 제외)
            if (inferredType === 'wiki') {
                try {
                    const titleQuery = query(
                        collection(db, COLLECTIONS.DOCUMENTS),
                        where('title', '==', editTitle),
                        where('visibility', '==', 'public'), // 퍼블릭 문서 중 중복 확인
                        where('isDeleted', '==', false)
                    );
                    const titleSnap = await getDocs(titleQuery);
                    const duplicateDoc = titleSnap.docs.find(d => d.id !== docId && d.id !== document?.id);

                    if (duplicateDoc) {
                        toast.error(`'${editTitle}' 제목을 가진 위키 문서가 이미 존재합니다. 다른 제목을 입력해주세요.`);
                        setIsSaving(false);
                        return;
                    }
                } catch (err) {
                    console.error('[SAVE DEBUG] Duplicate title check failed:', err);
                }
            }

            const visibility = inferredType === 'daily' ? 'private' : (document?.visibility || 'public');

            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, COLLECTIONS.DOCUMENTS, docId);
                const sfDoc = await transaction.get(docRef);

                if (!sfDoc.exists()) {
                    // 유령 문서가 실제 생성되는 트랜잭션 (ID가 'new-' 또는 'daily-'로 시작하는 경우)
                    if (docId.startsWith('new-') || docId.startsWith('daily-')) {
                        transaction.set(docRef, {
                            title: editTitle,
                            content: finalContent,
                            docType: inferredType,
                            category: inferredType === 'wiki' ? editCategory : null,
                            authorId: user.uid,
                            authorName: customName || user.displayName || user.email?.split('@')[0] || 'Anonymous',
                            visibility: docId.startsWith('daily-') ? 'private' : visibility, // Enforce private for daily
                            properties: {},
                            searchKeywords: searchKeywords,
                            outgoingLinks: titles,
                            outgoingLinkIds: ids,
                            contributorIds: [user.uid], // Initialize with author
                            isDeleted: false,
                            deletedAt: null,
                            version: 1,
                            createdAt: serverTimestamp(),
                            updatedAt: serverTimestamp(),
                            // [New] Auto-extract cover image
                            coverImage: extractCoverImageId(finalContent)
                        });
                        return;
                    }
                    throw new Error("Document does not exist!");
                }

                const data = sfDoc.data() as WikiDocument;

                // Optimistic locking using version
                const currentVersion = data.version || 0;
                const localVersion = document.version || 0;

                if (currentVersion > localVersion) {
                    throw new Error("Conflict: Document has been modified by someone else.");
                }

                transaction.update(docRef, {
                    content: finalContent,
                    title: editTitle,
                    docType: inferredType,
                    category: inferredType === 'wiki' ? editCategory : null,
                    visibility: visibility,
                    updatedAt: serverTimestamp(),
                    version: currentVersion + 1,
                    outgoingLinks: titles,
                    outgoingLinkIds: ids,
                    searchKeywords: searchKeywords,
                    contributorIds: arrayUnion(user.uid), // Track contributor
                    // [New] Auto-extract cover image
                    coverImage: extractCoverImageId(finalContent)
                });

                // --- Revision History (Snapshot with Squash Logic) ---
                const revisionsRef = collection(db, COLLECTIONS.DOCUMENTS, docId, COLLECTIONS.REVISIONS);
                const q = query(revisionsRef, orderBy('createdAt', 'desc'), limit(1));
                const revisionSnap = await getDocs(q);

                let shouldSquash = false;
                if (!revisionSnap.empty) {
                    const lastRevDoc = revisionSnap.docs[0];
                    const lastRevData = lastRevDoc.data();
                    const lastUpdate = lastRevData.createdAt?.toDate();
                    const now = new Date();

                    // Squash Condition: Same author AND within 5 minutes (BUT NOT IF IT'S A RESTORE OPERATION)
                    if (!isRestore && lastRevData.authorId === user.uid && lastUpdate && (now.getTime() - lastUpdate.getTime() < 5 * 60 * 1000)) {
                        shouldSquash = true;
                        transaction.update(lastRevDoc.ref, {
                            content: finalContent,
                            title: editTitle,
                            createdAt: serverTimestamp(), // Update time to latest edit in the squash window
                        });
                    }
                }

                if (!shouldSquash) {
                    const newRevRef = doc(collection(db, COLLECTIONS.DOCUMENTS, docId, COLLECTIONS.REVISIONS));
                    transaction.set(newRevRef, {
                        content: finalContent,
                        title: editTitle,
                        authorId: user.uid,
                        authorName: customName || user.displayName || user.email?.split('@')[0] || 'Anonymous',
                        createdAt: serverTimestamp(),
                        version: currentVersion + 1,
                        isRestored: isRestore // [NEW] Flag to identify restored revisions
                    });
                }
            });

            // [Fix] Trigger WikiMap Refresh Event
            // This ensures useWikiMap hooks in other components (like ReflectEditor)
            // fetch the latest document list immediately.
            window.dispatchEvent(new CustomEvent('wiki-updated'));

            // 3. Rename 동기화 (문서 제목이 변경된 경우에만)
            const isRenamed = !docId.startsWith('new-') && document && editTitle !== document.title;
            if (isRenamed) {
                const oldTitle = document.title;
                const batch = writeBatch(db);

                // 해당 문서를 참조하고 있는 모든 공유 문서 찾기 (authorId 제한 없이)
                const docsRef = collection(db, COLLECTIONS.DOCUMENTS);
                const q = query(
                    docsRef,
                    where('outgoingLinks', 'array-contains', oldTitle)
                );
                const querySnapshot = await getDocs(q);

                querySnapshot.forEach((refDoc) => {
                    const refData = refDoc.data() as WikiDocument;
                    // outgoingLinks 배열에서 이전 제목 교체
                    const newOutgoingLinks = refData.outgoingLinks?.map(link =>
                        link === oldTitle ? editTitle : link
                    );

                    // 본문에서도 [[이전 제목]] -> [[새 제목]]으로 교체
                    // ID 형식 링크도 처리: [[docId|이전 제목]] -> [[새 제목]]
                    let newContent = refData.content;
                    const oldLinkPattern = `[[${oldTitle}]]`;
                    const newLinkPattern = `[[${editTitle}]]`;
                    newContent = newContent.split(oldLinkPattern).join(newLinkPattern);

                    // ID 형식 링크 교체: [[xxxxx|이전 제목]] -> [[xxxxx|새 제목]]
                    const idLinkRegex = new RegExp(`\\[\\[([^|\\]]+)\\|${oldTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\]\\]`, 'g');
                    newContent = newContent.replace(idLinkRegex, `[[$1|${editTitle}]]`);

                    batch.update(doc(db, COLLECTIONS.DOCUMENTS, refDoc.id), {
                        outgoingLinks: newOutgoingLinks,
                        content: newContent,
                        updatedAt: serverTimestamp()
                    });
                });

                if (querySnapshot.size > 0) {
                    await batch.commit();
                }
            }

            // 저장 성공 시 임시저장본 삭제
            await autoSave.clearDraft();
            await releaseLock();
            stopHeartbeat();
            setIsEditing(false);
            toast.success('저장되었습니다.');

        } catch (e: any) {
            console.error("Error updating document: ", e);
            console.error("Error Name:", e.name);
            console.error("Error Message:", e.message);
            console.error("Error Stack:", e.stack);

            if (e.name === 'FetchError' || e.message.includes('Failed to fetch') || e.code === 'unavailable') {
                toast.error('네트워크 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해주세요.');
            } else if (e.message.includes("Conflict")) {
                toast.error("누군가 문서를 수정했습니다. 최신 내용을 확인해주세요. (새로고침 권장)");
            } else {
                toast.error(`저장 중 오류가 발생했습니다: ${e.message}`);
            }
        } finally {
            setIsSaving(false);
        }
    };

    // 이탈 모달: 저장 후 나가기
    const handleSaveAndLeave = async () => {
        await handleSave();
        setIsLeaveConfirmOpen(false);
    };

    // 이탈 모달: 저장하지 않고 나가기 (임시저장 삭제)
    const handleDiscardAndLeave = async () => {
        await autoSave.clearDraft();
        setIsEditing(false);
        if (document) {
            setEditContent(document.content);
            setEditTitle(document.title);
            setEditCategory(document.category || 'general');
        }
        stopHeartbeat();
        await releaseLock();
        setIsLeaveConfirmOpen(false);
    };

    // 이탈 모달: 편집 계속
    const handleContinueEditing = () => {
        setIsLeaveConfirmOpen(false);
    };

    // 문서 공개 범위 변경 핸들러
    const handleVisibilityChange = async (newVisibility: Visibility) => {
        if (!document || !user) return;

        // 권한 체크: 작성자만 변경 가능
        if (document.authorId !== user.uid) {
            toast.error('작성자만 공개 범위를 변경할 수 있습니다.');
            return;
        }

        // [Phase 2] Privatization Loophole Prevention
        // Block "Public -> Private" if multiple contributors exist
        if (document.visibility === 'public' && newVisibility === 'private') {
            const contributors = document.contributorIds || [];
            // If there are other contributors besides the author (or current user), block it
            // Simple check: if more than 1 contributor => blocked
            // Or stricter: if anyone other than me contributed => blocked
            const otherContributors = contributors.filter(id => id !== user.uid);

            if (otherContributors.length > 0) {
                toast.error('다른 사용자가 기여한 문서는 지식 보존을 위해 비공개로 전환할 수 없습니다.');
                return;
            }
        }

        // [Phase 2] Private -> Public Confirmation
        if (document.visibility === 'private' && newVisibility === 'public') {
            const confirmMsg = "문서를 공개하시겠습니까?\n\n공개된 문서는 다른 사용자가 기여할 경우 지식 보존을 위해 다시 비공개로 전환할 수 없습니다.\n\n동의하십니까?";
            if (!(await confirmDialog(confirmMsg))) {
                return;
            }
        }

        // Conflict Check: Prevent setting to public if a public doc with the same title exists
        if (newVisibility === 'public') {
            const docsRef = collection(db, COLLECTIONS.DOCUMENTS);
            const q = query(
                docsRef,
                where('title', '==', document.title),
                where('visibility', '==', 'public')
            );

            try {
                const querySnapshot = await getDocs(q);
                if (!querySnapshot.empty) {
                    // Check if the found doc is NOT the current doc (it shouldn't be, since current is private, but safe check)
                    const existingPublicDoc = querySnapshot.docs.find(d => d.id !== document.id);
                    if (existingPublicDoc) {
                        toast.error('이미 같은 이름의 공개 문서가 존재하여 공개로 전환할 수 없습니다. 문서 제목을 변경하거나 기존 공개 문서를 확인해주세요.');
                        return;
                    }
                }
            } catch (error) {
                console.error("Error checking for public collisions:", error);
                toast.error("중복 검사 중 오류가 발생했습니다.");
                return;
            }
        }

        try {
            const docRef = doc(db, COLLECTIONS.DOCUMENTS, document.id);
            await runTransaction(db, async (transaction) => {
                const sfDoc = await transaction.get(docRef);
                if (!sfDoc.exists()) throw "Document does not exist!";
                transaction.update(docRef, {
                    visibility: newVisibility,
                    updatedAt: serverTimestamp()
                });
            });
            // 로컬 상태 업데이트는 onSnapshot이 처리함
        } catch (error) {
            console.error("Error updating visibility:", error);
            toast.error("공개 범위 변경 중 오류가 발생했습니다.");
        }
    };

    const handleDelete = async () => {
        if (!user || !document) return;

        // [Phase 2] Vandalism Protection
        // Restrict "Delete" on Public docs to Admin only
        if (document.visibility === 'public' && !isAdmin) {
            toast.error('공개 문서는 관리자만 삭제할 수 있습니다. 문서 내용을 비우거나 관리자에게 아카이브 요청을 해주세요.');
            return;
        }

        if (!(await confirmDialog('문서를 휴지통으로 이동하시겠습니까? (복구 가능)'))) {
            return;
        }

        setIsSaving(true);
        try {
            // Soft Delete Implementation
            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, COLLECTIONS.DOCUMENTS, docId);
                transaction.update(docRef, {
                    isDeleted: true,
                    updatedAt: serverTimestamp(),
                    deletedAt: serverTimestamp(),
                    deletedBy: user.uid
                });
            });
            toast.success('문서가 휴지통으로 이동되었습니다.');
            router.push('/');
        } catch (e) {
            console.error("Error deleting document: ", e);
            toast.error('삭제 중 오류가 발생했습니다.');
        } finally {
            setIsSaving(false);
            stopHeartbeat();
        }
    };

    const handleRestore = async () => {
        if (!user || !document) return;

        if (!(await confirmDialog('문서를 복원하시겠습니까?'))) {
            return;
        }

        setIsSaving(true);
        try {
            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, COLLECTIONS.DOCUMENTS, docId);
                transaction.update(docRef, {
                    isDeleted: false,
                    deletedAt: null,
                    deletedBy: null,
                    updatedAt: serverTimestamp()
                });
            });
            toast.success('문서가 복원되었습니다.');
        } catch (e) {
            console.error("Error restoring document: ", e);
            toast.error('복원 중 오류가 발생했습니다.');
        } finally {
            setIsSaving(false);
            stopHeartbeat();
        }
    };

    const handlePurge = async () => {
        if (!user || !document || !isAdmin) return;

        if (!(await confirmDialog('경고: 이 문서를 영구적으로 삭제하시겠습니까?\n이 작업은 변경 이력(Revision History)을 포함한 모든 데이터를 삭제하며, 되돌릴 수 없습니다.'))) {
            return;
        }

        setIsSaving(true);
        try {
            const token = await user.getIdToken();
            const response = await fetch(`/api/admin/purge?docId=${docId}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });

            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(errorData.error || 'Purge failed');
            }

            toast.success('문서가 영구적으로 삭제되었습니다.');
            router.push('/');
        } catch (e: any) {
            console.error("Error purging document: ", e);
            toast.error(`영구 삭제 중 오류가 발생했습니다: ${e.message}`);
        } finally {
            setIsSaving(false);
            stopHeartbeat();
        }
    };

    // Attachment Logic

    const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
        const files = e.target.files;
        if (!files || files.length === 0) return;

        // 권한 체크: 멤버 이상만 업로드 가능
        if (userRole === 'guest') {
            toast.error('손님(Guest) 계정은 파일을 업로드할 수 없습니다. 관리자 승인을 기다려주세요.');
            return;
        }

        const file = files[0];
        // 50MB 용량 제한 체크
        if (file.size > 50 * 1024 * 1024) {
            toast.error('파일 크기는 50MB를 초과할 수 없습니다.');
            return;
        }

        setIsUploading(true);
        const formData = new FormData();
        formData.append('file', file);

        try {
            const token = await user?.getIdToken();
            const response = await fetch('/api/upload', {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${token}`
                },
                body: formData
            });

            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(errorData.message || errorData.error || 'Upload failed');
            }

            const data = await response.json();

            // Firestore 업데이트 (첨부파일 메타데이터 추가)
            const newAttachment = {
                fileId: data.fileId,
                name: data.name,
                url: data.webViewLink,
                type: file.type,
                uploadedAt: new Date() // Firestore에서는 서버 타임스탬프로 변환되거나 클라이언트 Date 객체로 저장됨
            };

            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, COLLECTIONS.DOCUMENTS, docId);
                const sfDoc = await transaction.get(docRef);
                if (!sfDoc.exists()) throw "Document does not exist!";

                transaction.update(docRef, {
                    attachments: arrayUnion(newAttachment),
                    updatedAt: serverTimestamp()
                });
            });

            toast.success('파일이 업로드되었습니다.');
        } catch (error: any) {
            console.error('File upload error:', error);
            toast.error(`파일 업로드 중 오류가 발생했습니다: ${error.message}`);
        } finally {
            setIsUploading(false);
            // Input 초기화
            e.target.value = '';
        }
    };

    // ── 상담 녹음 완료 핸들러 ──
    const isDailyNote = document?.docType === 'daily';

    const handleRecordingComplete = async (blob: Blob, recStartTime: string, durationSeconds: number) => {
        if (!user || !document) return;

        // [Safety] Vercel Serverless Limit (4.5MB) Check
        // 4MB = 4 * 1024 * 1024 bytes
        if (blob.size > 4 * 1024 * 1024) {
            toast.error('녹음 파일이 너무 큽니다 (4MB 제한). 짧게 끊어서 녹음해주세요.');
            return;
        }

        try {
            // 1. 파일명 생성: 상담녹음_HH-mm_길이.ext
            const durationLabel = formatDurationKorean(durationSeconds);
            const safeTime = recStartTime.replace(':', '-');

            // MIME 타입에 따른 확장자 결정 (iOS 대응)
            const ext = blob.type.includes('mp4') ? 'mp4' : 'webm';
            const fileName = `상담녹음_${safeTime}_${durationLabel}.${ext}`;

            const file = new File([blob], fileName, { type: blob.type });

            // 2. 구글드라이브 업로드 (기존 API 재사용)
            const formData = new FormData();
            formData.append('file', file);

            const token = await user.getIdToken();
            const response = await fetch('/api/upload', {
                method: 'POST',
                headers: { 'Authorization': `Bearer ${token}` },
                body: formData,
            });

            if (!response.ok) {
                const errorText = await response.text();
                let errorMessage = 'Upload failed';
                try {
                    const errorData = JSON.parse(errorText);
                    errorMessage = errorData.message || errorData.error || errorMessage;
                } catch (e) {
                    errorMessage = `Server Error (${response.status}): ${errorText.slice(0, 50)}`;
                }
                throw new Error(errorMessage);
            }

            const data = await response.json();

            // 3. Firestore 첨부파일 메타데이터 추가
            const newAttachment = {
                fileId: data.fileId,
                name: data.name,
                url: data.webViewLink,
                type: file.type,
                uploadedAt: new Date(),
            };

            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, COLLECTIONS.DOCUMENTS, docId);
                const sfDoc = await transaction.get(docRef);

                // [Fix] Determine base content:
                // If editing, use local 'editContent' (unsaved changes).
                // If viewing, use server 'sfDoc.data().content'.
                // This prevents overwriting local edits with stale server data.
                let baseContent = '';
                if (isEditing) {
                    baseContent = editContent;
                } else if (sfDoc.exists()) {
                    baseContent = sfDoc.data().content || '';
                }

                // [Fix] If document doesn't exist (e.g. new Daily Note), create it first !
                if (!sfDoc.exists()) {
                    const initialData = {
                        title: document.title || 'Untitled',
                        content: '', // Will be updated below
                        docType: document.docType || 'general',
                        userId: user.uid,
                        createdAt: serverTimestamp(),
                        updatedAt: serverTimestamp(),
                        attachments: [newAttachment],
                    };

                    // Use smart numbering for the first line
                    const prefix = typeof detectNextNumbering === 'function' ? detectNextNumbering(baseContent) : '';
                    const recordingLine = `${prefix}🎙️ ${recStartTime} (${durationLabel}) [📥 다운로드](${data.webViewLink})`;

                    initialData.content = baseContent + recordingLine;

                    transaction.set(docRef, initialData);
                    return;
                }

                // Normal Update
                // Reuse baseContent determined above
                const prefix = typeof detectNextNumbering === 'function' ? detectNextNumbering(baseContent) : '\n';
                const downloadLink = data.webViewLink;
                const recordingLine = `${prefix}🎙️ ${recStartTime} (${durationLabel}) [📥 다운로드](${downloadLink})`;

                transaction.update(docRef, {
                    attachments: arrayUnion(newAttachment),
                    content: baseContent + recordingLine,
                    updatedAt: serverTimestamp(),
                });
            });

            // 5. 로컬 상태 갱신 (content가 onSnapshot으로 자동 반영되므로 alert만)
            toast.success(`녹음이 저장되었습니다. (${durationLabel})`);
        } catch (err: any) {
            console.error('Recording upload error:', err);
            // Show more detailed error for debugging
            const msg = err instanceof Error ? err.message : (typeof err === 'string' ? err : JSON.stringify(err));
            toast.error(`녹음 저장 중 오류가 발생했습니다: ${msg}`);
        }
    };

    const handleDeleteAttachment = async (fileId: string) => {
        if (!(await confirmDialog('정말 이 첨부파일을 삭제하시겠습니까? (서버 내 파일도 함께 삭제됩니다)'))) return;

        try {
            // 1. API Call to delete from Drive
            if (user) {
                try {
                    const token = await user.getIdToken();
                    const response = await fetch('/api/upload', {
                        method: 'DELETE',
                        headers: {
                            'Content-Type': 'application/json',
                            'Authorization': `Bearer ${token}`
                        },
                        body: JSON.stringify({ fileId })
                    });

                    if (!response.ok) {
                        const errorData = await response.json().catch(() => ({}));
                        console.error('Drive delete failed:', errorData);
                        // Optional: Ask user if they want to proceed with list removal if Drive delete fails
                        if (!(await confirmDialog('서버 파일 삭제에 실패했습니다. 그래도 목록에서 제거하시겠습니까?'))) {
                            return;
                        }
                    }
                } catch (apiError) {
                    console.error('Drive delete API error:', apiError);
                    if (!(await confirmDialog('서버 파일 삭제 요청 중 오류가 발생했습니다. 그래도 목록에서 제거하시겠습니까?'))) {
                        return;
                    }
                }
            }

            // 2. Firestore update (Remove from list)
            const attachmentToRemove = document?.attachments?.find(a => a.fileId === fileId);
            if (!attachmentToRemove) return;

            await runTransaction(db, async (transaction) => {
                const docRef = doc(db, COLLECTIONS.DOCUMENTS, docId);
                // Firestore arrayRemove issue: requires exact object match.
                // Instead, let's read, filter, and update.
                // Ideally we should read inside transaction to be safe, but since we are just removing by ID,
                // and we want to preserve other concurrent additions if possible, strictly we need to read.
                // However, detailed read might be expensive. arrayRemove is best if we had the exact object.
                // Let's use the filter approach for now as in the original code.

                // Better approach for concurrency: Read inside transaction
                const sfDoc = await transaction.get(docRef);
                if (!sfDoc.exists()) throw "Document does not exist!";

                const currentAttachments = sfDoc.data().attachments || [];
                const updatedAttachments = currentAttachments.filter((a: any) => a.fileId !== fileId);

                transaction.update(docRef, {
                    attachments: updatedAttachments,
                    updatedAt: serverTimestamp()
                });
            });
            toast.success('첨부파일이 삭제되었습니다.');
        } catch (error) {
            console.error('Attachment delete error:', error);
            toast.error('삭제 중 오류가 발생했습니다.');
        }
    };

    // ─── 음성 명령 컨텍스트 등록 (25개 중 16개 페이지 전용 명령) ───
    const { registerHandlers, unregisterHandlers } = useVoiceCommandContext();
    useEffect(() => {
        registerHandlers({
            // 에디터 제어
            onEditStart: () => handleEditClick(),
            onEditCancel: () => handleCancelClick(),
            onSaveDocument: () => handleSave(),
            onInsertNewline: () => {
                if (isEditing) setEditContent(prev => prev + '\n');
            },
            onInsertParagraph: () => {
                if (isEditing) setEditContent(prev => prev + '\n\n');
            },
            onInsertChecklist: () => {
                if (isEditing) setEditContent(prev => prev + '\n- [ ] ');
            },
            // 문서 관리
            onSetPublic: () => handleVisibilityChange('public'),
            onSetPrivate: () => handleVisibilityChange('private'),
            onDelete: () => handleDelete(),
            onOpenHistory: () => setIsHistoryModalOpen(true),
            // 녹음 제어
            onConsentRecordStart: () => setIsConsentModalOpen(true),
            onConsentRecordEnd: () => setIsConsentModalOpen(false),
        });
        return () => unregisterHandlers();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [isEditing]);

    return {
        // state
        document,
        isEditing,
        editContent,
        editTitle,
        editCategory,
        isSaving,
        loadingDoc,
        isTocOpen,
        isHistoryModalOpen,
        isUploading,
        isConsentModalOpen,
        revisions,
        shadowedDocId,
        // derived
        docType,
        isDaily,
        isDailyNote,
        isAdmin,
        headerVariant,
        buttonClass,
        badgeClass,
        // auth state
        user,
        userRole,
        customName,
        loading,
        // lock state
        lockInfo,
        // setters needed by JSX
        setIsTocOpen,
        setIsHistoryModalOpen,
        setIsConsentModalOpen,
        setEditContent,
        setEditTitle,
        setEditCategory,
        // handlers
        handleEditClick,
        handleCancelClick,
        handleSave,
        handleVisibilityChange,
        handleDelete,
        handleRestore,
        handlePurge,
        handleFileUpload,
        handleRecordingComplete,
        handleDeleteAttachment,
        // auto-save
        autoSave,
        isLeaveConfirmOpen,
        isDraftRecoveryOpen,
        handleSaveAndLeave,
        handleDiscardAndLeave,
        handleContinueEditing,
        handleDraftRecover,
        handleDraftDiscard,
    };
}
