import { logInfo, logError } from '../../utils';

/**
 * Chat prompt 의 *첨부 파일* 처리 — webview 가 보낸 base64 파일들을 type 별로
 * 분류해 (PDF / text / image / unknown) 적절한 형태로 변환.
 *
 *   - PDF: pdf-parse v2 로 텍스트 추출 시도 → 텍스트 없으면 페이지 screenshot
 *     8장까지 vision 모델 입력으로 fallback.
 *   - Text-like (.md, .json, .ts 등): base64 → utf-8 디코딩 후 ```code``` 블록.
 *   - Image: 그대로 vision content array 에 추가.
 *   - Unknown: 파일명만 기록 (사용자에게 형식 안내).
 *
 * 옛 코드: sidebarProvider 의 `_handlePrompt` 안 90줄짜리 if/else 블록 inline.
 * 분리해서 (a) PDF parsing 흐름 단위 테스트 가능, (b) 새 파일 타입 추가 시
 * 한 곳만 수정.
 *
 * 반환값: `textContents` 는 prompt 본문에 합칠 텍스트 블록 목록 (각 항목이 한
 * 파일에 대응). `imageFiles` 는 vision content 로 넘길 image 배열 (없으면 빈 배열).
 */
export interface AttachmentResult {
    /** prompt 에 합칠 텍스트 블록들 (PDF 추출 텍스트, decode 된 코드 파일 등). */
    textContents: string[];
    /** vision content 로 사용할 image attachments (PDF→screenshots 도 포함). */
    imageFiles: any[];
}

const TEXT_FILE_EXTENSIONS = /\.(txt|md|csv|json|js|ts|jsx|tsx|html|css|py|java|rs|go|yaml|yml|xml|toml|sql|sh)$/i;

export async function processAttachments(files: any[] | undefined | null): Promise<AttachmentResult> {
    if (!Array.isArray(files) || files.length === 0) {
        return { textContents: [], imageFiles: [] };
    }
    const textContents: string[] = [];
    const images: any[] = [];

    for (const file of files) {
        const name = file.name?.toLowerCase() || '';
        const type = file.type || '';

        if (name.endsWith('.pdf') || type === 'application/pdf') {
            await processPdfFile(file, textContents, images);
        } else if (
            type.startsWith('text/')
            || type === 'application/json'
            || TEXT_FILE_EXTENSIONS.test(name)
        ) {
            try {
                const decoded = Buffer.from(file.data, 'base64').toString('utf-8');
                textContents.push(`\n[FILE: ${file.name}]\n\`\`\`\n${decoded}\n\`\`\``);
            } catch (decodeError: any) {
                logError('Text file decode failed.', { fileName: file.name, error: decodeError?.message });
                textContents.push(`\n[FILE: ${file.name}]\n(디코딩 오류)`);
            }
        } else if (type.startsWith('image/')) {
            images.push(file);
        } else {
            textContents.push(`\n[ATTACHMENT: ${file.name}]\n(지원하지 않는 파일 형식: ${type || 'unknown'})`);
        }
    }

    return { textContents, imageFiles: images };
}

/**
 * PDF 한 개 처리. 텍스트 추출 → page screenshot vision fallback → 둘 다 실패 시
 * 안내 문구 1줄. 결과는 caller 의 textContents / images 배열에 push (in-place).
 *
 * pdf-parse v2 API: `new PDFParse(uint8) → load() → getText() / getScreenshot()`.
 * 메모리 보호 위해 vision fallback 은 최대 8 페이지로 cap.
 */
async function processPdfFile(file: any, textContents: string[], images: any[]): Promise<void> {
    let pdfTextOk = false;
    try {
        const { PDFParse } = require('pdf-parse');
        const rawBuffer = Buffer.from(file.data, 'base64');
        const uint8 = new Uint8Array(rawBuffer.buffer, rawBuffer.byteOffset, rawBuffer.byteLength);
        const parser = new PDFParse(uint8);
        await parser.load();
        const textResult = await parser.getText();
        const extracted = (typeof textResult === 'string' ? textResult : (textResult?.text || '')).trim();
        const cleanText = extracted.replace(/\n*-- \d+ of \d+ --\n*/g, '\n').trim();
        if (cleanText && cleanText.length > 30) {
            textContents.push(`\n[PDF: ${file.name}]\n${cleanText}`);
            logInfo('PDF text extracted successfully.', { fileName: file.name, chars: cleanText.length });
            pdfTextOk = true;
        }

        // Vision fallback — text layer 없는 PDF (스캔본 등) 의 마지막 수단.
        if (!pdfTextOk) {
            logInfo('PDF has no text layer. Extracting page screenshots for vision analysis.', { fileName: file.name });
            const screenshots = await parser.getScreenshot({ page: 1 });
            if (screenshots?.pages && screenshots.pages.length > 0) {
                const maxPages = Math.min(screenshots.pages.length, 8); // 메모리 보호: 최대 8페이지
                for (let i = 0; i < maxPages; i++) {
                    const page = screenshots.pages[i];
                    if (page?.data) {
                        const pageBase64 = Buffer.from(page.data).toString('base64');
                        images.push({
                            name: `${file.name}_page${i + 1}.png`,
                            type: 'image/png',
                            data: pageBase64,
                        });
                    }
                }
                textContents.push(`\n[PDF: ${file.name}]\n(이미지 기반 PDF ${screenshots.total}페이지 중 ${maxPages}페이지를 이미지로 추출하여 Vision 분석합니다. 각 페이지 이미지를 참조하여 문서의 내용을 상세히 분석하고 한국어로 정리하세요.)`);
                logInfo('PDF vision fallback: extracted page screenshots.', { fileName: file.name, totalPages: screenshots.total, extracted: maxPages });
                pdfTextOk = true;
            }
        }
    } catch (pdfError: any) {
        logError('PDF processing failed.', { fileName: file.name, error: pdfError?.message || String(pdfError) });
    }

    if (!pdfTextOk) {
        textContents.push(`\n[PDF: ${file.name}]\n(PDF 분석에 실패했습니다. 이 파일을 텍스트로 변환하여 다시 시도해주세요.)`);
    }
}
