import * as admin from 'firebase-admin';
import { onDocumentCreated } from 'firebase-functions/v2/firestore';
import { GoogleGenerativeAI } from '@google/generative-ai';
import { GoogleAIFileManager } from '@google/generative-ai/server';
import { google } from 'googleapis';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';

// 환경 변수 기반 구글 드라이브 인증 (서비스 어카운트 활용)
const getDriveAuth = () => {
    // 실제 운영 시 Google Cloud 환경에서는 기본 서비스 계정 자격 증명을 사용할 수 있지만,
    // Google Drive API 접근을 위해 명시적인 서비스 계정 권한이 필요할 수 있습니다.
    // 여기서는 기본 인증(Default Credentials)을 우선 사용하되 로컬/테스트 환경 구성을 의존합니다.
    const auth = new google.auth.GoogleAuth({
        scopes: ['https://www.googleapis.com/auth/drive.readonly'],
    });
    return google.drive({ version: 'v3', auth });
};

export const processInsuranceQuery = onDocumentCreated({
    document: 'jobs/{jobId}',
    timeoutSeconds: 540, // 9분 타임아웃 
    memory: '1GiB',      // 메모리 용량
    region: 'asia-northeast3' // 서울 리전 최적화
}, async (event) => {
    const snapshot = event.data;
    if (!snapshot) {
        console.log("No data associated with the event");
        return;
    }

    const jobData = snapshot.data();
    const jobId = snapshot.id;

    // pdf_query 가 아니거나 상태가 pending이 아니면 패스
    if (jobData.type !== 'pdf_query' || jobData.status !== 'pending') {
        return;
    }

    const db = admin.firestore();
    const jobRef = db.collection('jobs').doc(jobId);

    try {
        console.log(`Starting processing for job: ${jobId}`);

        // 1. 보험 상품 메타데이터 로드
        const metadataSnapshot = await db.collection('insurance_metadata')
            .where('companyId', '==', jobData.companyId)
            .where('productId', '==', jobData.productId)
            .limit(1)
            .get();

        if (metadataSnapshot.empty) {
            throw new Error(`Insurance metadata not found for ${jobData.companyId}_${jobData.productId}`);
        }

        const metadata = metadataSnapshot.docs[0].data();
        const driveFileId = metadata.driveFileId;

        if (!driveFileId) {
            throw new Error(`Google Drive File ID is missing in metadata for ${jobData.companyId}_${jobData.productId}`);
        }

        // 2. Gemini API 키 확인
        const apiKey = process.env.GEMINI_API_KEY;
        if (!apiKey) {
            throw new Error('GEMINI_API_KEY environment variable is missing.');
        }

        const genAI = new GoogleGenerativeAI(apiKey);
        const fileManager = new GoogleAIFileManager(apiKey);

        // 3. 캐시 확인 로직
        const now = admin.firestore.Timestamp.now();
        const cacheQuery = await db.collection('gemini_file_cache')
            .where('driveFileId', '==', driveFileId)
            .where('expireAt', '>', now)
            .limit(1)
            .get();

        let geminiFileUri = '';
        let geminiMimeType = '';

        if (!cacheQuery.empty) {
            // Cache Hit
            const cacheDoc = cacheQuery.docs[0].data();
            geminiFileUri = cacheDoc.geminiFileUri;
            geminiMimeType = cacheDoc.mimeType;
            console.log(`Cache Hit! Reusing Gemini file: ${geminiFileUri}`);
        } else {
            // Cache Miss: 다운로드 및 업로드
            console.log(`Cache Miss! Downloading from Google Drive: ${driveFileId}`);
            const drive = getDriveAuth();

            const tempFilePath = path.join(os.tmpdir(), `${driveFileId}.pdf`);
            const dest = fs.createWriteStream(tempFilePath);

            // 드라이브에서 PDF 파일 다운로드
            const response = await drive.files.get({
                fileId: driveFileId,
                alt: 'media',
            }, { responseType: 'stream' });

            await new Promise((resolve, reject) => {
                response.data
                    .on('end', () => resolve(true))
                    .on('error', err => reject(err))
                    .pipe(dest);
            });

            console.log(`Downloaded to temp file: ${tempFilePath}, Uploading to Gemini File API...`);

            // Gemini File API 업로드
            const uploadResponse = await fileManager.uploadFile(tempFilePath, {
                mimeType: 'application/pdf',
                displayName: `${jobData.companyId}_${jobData.productId}.pdf`,
            });

            // 처리 대기 (Optional)
            let fileState = await fileManager.getFile(uploadResponse.file.name);
            while (fileState.state === 'PROCESSING') {
                await new Promise((resolve) => setTimeout(resolve, 2000));
                fileState = await fileManager.getFile(uploadResponse.file.name);
            }

            if (fileState.state === 'FAILED') {
                throw new Error('Gemini File API processing failed for uploaded Document.');
            }

            console.log(`Upload complete: ${uploadResponse.file.uri}`);

            geminiFileUri = uploadResponse.file.uri;
            geminiMimeType = uploadResponse.file.mimeType;

            // 로컬 임시 파일 삭제
            if (fs.existsSync(tempFilePath)) {
                fs.unlinkSync(tempFilePath);
            }

            // 4. 캐시 저장 (48시간 TTL)
            const expireAt = new Date();
            expireAt.setHours(expireAt.getHours() + 48);

            await db.collection('gemini_file_cache').add({
                fileKey: `${jobData.companyId}_${jobData.productId}_${driveFileId}`,
                companyId: jobData.companyId,
                productId: jobData.productId,
                driveFileId: driveFileId,
                geminiFileId: uploadResponse.file.name,
                geminiFileUri: geminiFileUri,
                mimeType: geminiMimeType,
                createdAt: admin.firestore.FieldValue.serverTimestamp(),
                expireAt: admin.firestore.Timestamp.fromDate(expireAt)
            });
        }

        // 5. LLM 질의 (롱 컨텍스트) — v2 §8-2 시스템 프롬프트 적용
        console.log(`Initiating LLM generation for question: ${jobData.question}`);
        const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" }); // v2 §5 C형 심층 분석

        // ⚠️ v2 Spec §8-2 절대 변경 금지 프롬프트
        const systemPrompt = `당신은 보험 약관 분석 전문가입니다.
아래 규칙을 반드시 따르세요:

1. 제공된 약관 원문에 명시된 내용만 답변합니다.
2. 원문에 없는 내용은 절대 추정하거나 생성하지 않습니다.
3. 확인 불가 시 반드시 다음 형식으로 답변합니다:
   "제공된 약관에서 해당 내용을 확인할 수 없습니다.
    [어떤 정보가 부족한지 구체적으로 설명]"
4. 유사한 내용이 있어도 정확히 일치하지 않으면 언급하지 않습니다.
5. 답변 마지막에 반드시 출처를 명시합니다.
   형식: "※ 출처: {상품명} 약관 {페이지}p"
6. "아마도", "추정", "일반적으로", "보통은", "대개", "~인 것 같" 표현을 절대 사용하지 않습니다.
7. 모든 특약 관련 답변에 반드시 다음 문구를 볼드로 포함하세요: **이 특약에 가입되어 있는지 보험증권을 확인하세요.**
   "선택특약", "추가특약", "특별약관" 등 특약 관련 키워드가 응답에 포함될 때 필수 삽입합니다.`;

        const result = await model.generateContent([
            systemPrompt,
            {
                fileData: {
                    mimeType: geminiMimeType,
                    fileUri: geminiFileUri
                }
            },
            `질문: ${jobData.question}`
        ]);

        let answerText = result.response.text();
        console.log("LLM generation complete.");

        // ── v2 §8-3 답변 자동 검증 ──────────────────────────────────
        const UNCERTAIN_PHRASES = ['아마도', '추정', '일반적으로', '보통은', '대개', '인 것 같'];
        const hasUncertain = UNCERTAIN_PHRASES.some(p => answerText.includes(p));
        const hasSource = answerText.includes('※ 출처:') || answerText.includes('확인할 수 없습니다');

        if (hasUncertain) {
            console.warn('⚠️ 불확실 표현 감지 — 답변 재처리 또는 확인불가 처리');
            answerText = '제공된 약관에서 해당 내용을 확인할 수 없습니다. 약관 원문을 직접 확인해 주세요.';
        } else if (!hasSource) {
            console.warn('⚠️ 출처 누락 — 면책 문구로 보완');
        }

        // ── v2 §9 법적 면책 문구 자동 삽입 ────────────────────────────
        const disclaimer = `\n\n※ 이 답변은 약관 원문 검색 결과이며, 실제 보험금 지급 여부는 보험사 심사 기준에 따릅니다. 청구 가능 여부는 반드시 보험사에 확인하세요.`;
        const finalAnswer = answerText.includes('면책') ? answerText : answerText + disclaimer;

        // 판매 중단 상품 배지 정보
        const isSalesStopped = metadata.isSalesStopped === true;

        // ── v2 §13 query_logs 감사 로그 저장 ───────────────────────────
        await db.collection('query_logs').add({
            agentId: jobData.userId,
            sessionId: jobId, // Job ID를 세션 ID로 임시 사용
            question: jobData.question,
            queryType: jobData.queryType || 'DEEP_QUERY',
            sourceDocs: [driveFileId],
            answer: finalAnswer,
            confidenceScore: hasUncertain ? 0.0 : (hasSource ? 0.9 : 0.7),
            hasDisclaimerAttached: true,
            timestamp: admin.firestore.FieldValue.serverTimestamp(),
        });

        // 6. 결과 저장 (완료 상태)
        await jobRef.update({
            status: 'complete',
            answer: finalAnswer,
            isSalesStopped,
            hasDisclaimerAttached: true,
            updatedAt: admin.firestore.FieldValue.serverTimestamp()
        });

        console.log('🎉 Deep Query 완료:', jobId);

    } catch (error: any) {
        console.error(`Error processing job ${jobId}:`, error);
        // 실패 시 에러 저장 및 상태 변경
        await jobRef.update({
            status: 'failed',
            error: error.message || String(error),
            updatedAt: admin.firestore.FieldValue.serverTimestamp()
        });
    }
});
