"""PDF 미리보기 생성 워커 — LibreOffice Headless로 문서→PDF 변환"""

import subprocess
import shutil
from datetime import datetime, timezone
from pathlib import Path

from sqlalchemy.ext.asyncio import AsyncSession

from core.config import settings
from core.utils import setup_logger

logger = setup_logger("preview_worker")

# PDF 변환 대상 포맷
CONVERTIBLE_FORMATS = {
    "docx", "xlsx", "pptx", "odt", "ods", "odp",  # 안정 지원
    "odoc", "osheet", "hwp", "hwpx",                # 검증 필요
}
# 이미 PDF이거나 변환 불필요한 포맷
NATIVE_PDF = {"pdf"}
NATIVE_IMAGE = {"jpg", "jpeg", "png", "gif", "bmp", "tiff"}
TEXT_FORMATS = {"md", "txt", "csv", "json", "xml", "html"}

PREVIEW_DIR_NAME = "PKM/.preview"
TIMEOUT_SECONDS = 60


async def process(document_id: int, session: AsyncSession) -> None:
    """문서 PDF 미리보기 생성"""
    from models.document import Document

    doc = await session.get(Document, document_id)
    if not doc:
        logger.error(f"[preview] document_id={document_id} 없음")
        return

    fmt = doc.file_format.lower()

    # PDF/이미지/텍스트는 변환 불필요
    if fmt in NATIVE_PDF or fmt in NATIVE_IMAGE or fmt in TEXT_FORMATS:
        doc.preview_status = "ready" if fmt in NATIVE_PDF else "none"
        doc.preview_at = datetime.now(timezone.utc)
        await session.commit()
        return

    if fmt not in CONVERTIBLE_FORMATS:
        doc.preview_status = "none"
        await session.commit()
        logger.info(f"[preview] {doc.title} — 변환 불가 포맷: {fmt}")
        return

    # 원본 파일 경로
    source = Path(settings.nas_mount_path) / doc.file_path
    if not source.exists():
        doc.preview_status = "failed"
        await session.commit()
        logger.error(f"[preview] 원본 없음: {source}")
        return

    # 미리보기 디렉토리
    preview_dir = Path(settings.nas_mount_path) / PREVIEW_DIR_NAME
    preview_dir.mkdir(parents=True, exist_ok=True)
    output_path = preview_dir / f"{document_id}.pdf"

    doc.preview_status = "processing"
    await session.commit()

    # LibreOffice 변환
    try:
        tmp_dir = Path("/tmp/preview_work")
        tmp_dir.mkdir(exist_ok=True)

        # 한글 파일명 문제 방지 — 영문 임시 파일로 복사
        tmp_input = tmp_dir / f"input_{document_id}{source.suffix}"
        shutil.copy2(str(source), str(tmp_input))

        result = subprocess.run(
            [
                "libreoffice", "--headless", "--convert-to", "pdf",
                "--outdir", str(tmp_dir),
                str(tmp_input),
            ],
            capture_output=True,
            text=True,
            timeout=TIMEOUT_SECONDS,
        )

        tmp_input.unlink(missing_ok=True)

        if result.returncode != 0:
            raise RuntimeError(f"LibreOffice 변환 실패: {result.stderr[:200]}")

        # 변환 결과 찾기
        converted = tmp_dir / f"input_{document_id}.pdf"
        if not converted.exists():
            raise RuntimeError(f"변환 결과물 없음: {converted}")

        # 캐시로 이동
        shutil.move(str(converted), str(output_path))

        doc.preview_status = "ready"
        doc.preview_hash = doc.file_hash
        doc.preview_at = datetime.now(timezone.utc)
        await session.commit()
        logger.info(f"[preview] {doc.title} → PDF 변환 완료")

    except subprocess.TimeoutExpired:
        doc.preview_status = "failed"
        await session.commit()
        logger.error(f"[preview] {doc.title} — 변환 timeout ({TIMEOUT_SECONDS}s)")

    except Exception as e:
        doc.preview_status = "failed"
        await session.commit()
        logger.error(f"[preview] {doc.title} — 변환 실패: {e}")
