/**
 * 문서 잠금 유틸리티
 * 
 * 설계 문서: docs/decisions/260208-21.12-concurrent-editing.md
 * 생성일: 2026-02-08 21:14
 */

import {
    doc,
    runTransaction,
    Timestamp,
    Firestore
} from 'firebase/firestore';

// ============================================
// 타입 정의
// ============================================

export interface LockInfo {
    editingBy: string | null;
    editingByName: string | null;
    editingAt: Timestamp | null;
}

export interface AcquireLockResult {
    success: boolean;
    lockedBy?: string;
    lockedByName?: string;
    lockedAt?: Date;
}

// ============================================
// 상수
// ============================================

const LOCK_TIMEOUT_MS = 30 * 60 * 1000; // 30분

// ============================================
// 잠금 획득
// ============================================

export async function acquireLock(
    db: Firestore,
    docId: string,
    userId: string,
    userName: string
): Promise<AcquireLockResult> {
    const docRef = doc(db, 'documents', docId);

    try {
        const result = await runTransaction(db, async (transaction) => {
            const docSnap = await transaction.get(docRef);

            if (!docSnap.exists()) {
                throw new Error('Document not found');
            }

            const data = docSnap.data();

            // 이미 본인이 편집 중이면 성공
            if (data?.editingBy === userId) {
                return { success: true };
            }

            // 다른 사용자가 편집 중인 경우
            if (data?.editingBy && data.editingBy !== userId) {
                const editingAt = data.editingAt?.toDate();
                const now = new Date();

                // 30분 지났으면 만료된 잠금 → 새로 획득
                if (editingAt && (now.getTime() - editingAt.getTime()) > LOCK_TIMEOUT_MS) {
                    // 만료된 잠금, 새로 획득 진행
                } else {
                    // 유효한 잠금 존재 → 획득 실패
                    return {
                        success: false,
                        lockedBy: data.editingBy,
                        lockedByName: data.editingByName,
                        lockedAt: editingAt
                    };
                }
            }

            // 잠금 설정
            transaction.update(docRef, {
                editingBy: userId,
                editingByName: userName,
                editingAt: Timestamp.now()
            });

            return { success: true };
        });

        return result;
    } catch (error) {
        console.error('Failed to acquire lock:', error);
        throw error;
    }
}

// ============================================
// 잠금 해제
// ============================================

export async function releaseLock(
    db: Firestore,
    docId: string,
    userId: string
): Promise<boolean> {
    const docRef = doc(db, 'documents', docId);

    try {
        await runTransaction(db, async (transaction) => {
            const docSnap = await transaction.get(docRef);

            if (!docSnap.exists()) {
                return;
            }

            // 본인 잠금만 해제 가능
            if (docSnap.data()?.editingBy === userId) {
                transaction.update(docRef, {
                    editingBy: null,
                    editingByName: null,
                    editingAt: null
                });
            }
        });

        return true;
    } catch (error) {
        console.error('Failed to release lock:', error);
        return false;
    }
}

// ============================================
// Heartbeat (잠금 시간 갱신)
// ============================================

export async function updateLockHeartbeat(
    db: Firestore,
    docId: string,
    userId: string
): Promise<boolean> {
    const docRef = doc(db, 'documents', docId);

    try {
        await runTransaction(db, async (transaction) => {
            const docSnap = await transaction.get(docRef);

            // 본인 잠금만 갱신 가능
            if (docSnap.data()?.editingBy === userId) {
                transaction.update(docRef, {
                    editingAt: Timestamp.now()
                });
            }
        });

        return true;
    } catch (error) {
        console.error('Failed to update heartbeat:', error);
        return false;
    }
}

// ============================================
// 잠금 상태 확인
// ============================================

export function getLockStatus(data: LockInfo | undefined): {
    isLocked: boolean;
    isExpired: boolean;
    lockedByName: string | null;
    lockedSince: Date | null;
} {
    if (!data?.editingBy) {
        return {
            isLocked: false,
            isExpired: false,
            lockedByName: null,
            lockedSince: null
        };
    }

    const lockedAt = data.editingAt?.toDate() || null;
    const now = new Date();
    const isExpired = lockedAt
        ? (now.getTime() - lockedAt.getTime()) > LOCK_TIMEOUT_MS
        : false;

    return {
        isLocked: true,
        isExpired,
        lockedByName: data.editingByName,
        lockedSince: lockedAt
    };
}
