"""DOCX → PDF conversion — LibreOffice headless subprocess.

Reference-scripts'te PQC Gateway için aynı yaklaşım kullanıldı.
`soffice --headless --convert-to pdf` stabil, ücretsiz, format-preserving.

Önemli:
- LibreOffice başka bir instance çalışıyorsa `--headless` hâlâ çakışabilir;
  `-env:UserInstallation` ile izole profil veririz.
- Concurrent conversion için her çağrı kendi tmpdir'ini + user profile'ını
  alır — thread-safe.
- DOCX tüm stil/XML (satır numaralama, PAGE field, margins) PDF'e taşınır.
"""

from __future__ import annotations

import asyncio
import os
import shutil
import tempfile
import uuid
from pathlib import Path


class PdfConversionError(RuntimeError):
    """soffice exit code 0 değil veya çıktı dosyası üretmedi."""


class LibreOfficeNotFoundError(RuntimeError):
    """soffice binary bulunamadı."""


def _find_soffice() -> str:
    """Platform-agnostic soffice lookup: PATH → Homebrew → macOS bundle."""
    candidate = shutil.which("soffice") or shutil.which("libreoffice")
    if candidate:
        return candidate

    known_paths = [
        "/Applications/LibreOffice.app/Contents/MacOS/soffice",
        "/opt/homebrew/bin/soffice",
        "/usr/local/bin/soffice",
        "/usr/bin/libreoffice",
        "/usr/bin/soffice",
    ]
    for p in known_paths:
        if os.path.isfile(p) and os.access(p, os.X_OK):
            return p
    raise LibreOfficeNotFoundError(
        "LibreOffice (soffice) bulunamadı. macOS: `brew install --cask libreoffice`; "
        "Ubuntu: `apt install libreoffice`."
    )


def soffice_available() -> bool:
    try:
        _find_soffice()
        return True
    except LibreOfficeNotFoundError:
        return False


async def convert_docx_to_pdf(
    docx_bytes: bytes,
    *,
    timeout_seconds: int = 60,
) -> bytes:
    """DOCX bytes → PDF bytes. Concurrent-safe (her çağrı izole tmpdir)."""
    soffice = _find_soffice()

    with tempfile.TemporaryDirectory(prefix="pdf_conv_") as tmpdir:
        tmp_path = Path(tmpdir)
        # Concurrent conversion için ayrı UserInstallation dizini
        user_profile = tmp_path / "lo_profile"
        user_profile.mkdir()
        docx_path = tmp_path / f"input_{uuid.uuid4().hex[:8]}.docx"
        docx_path.write_bytes(docx_bytes)

        cmd = [
            soffice,
            f"-env:UserInstallation=file://{user_profile}",
            "--headless",
            "--convert-to",
            "pdf",
            "--outdir",
            str(tmp_path),
            str(docx_path),
        ]

        try:
            proc = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )
            stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout_seconds)
        except TimeoutError as exc:
            raise PdfConversionError(f"soffice {timeout_seconds}s içinde tamamlanamadı") from exc

        if proc.returncode != 0:
            err = (stderr or b"").decode("utf-8", errors="replace")
            raise PdfConversionError(f"soffice exit {proc.returncode}: {err[:500]}")

        # Output dosya: input_xxx.pdf (convert-to pdf aynı ismi kullanır, .docx → .pdf)
        pdf_path = docx_path.with_suffix(".pdf")
        if not pdf_path.exists():
            raise PdfConversionError(
                f"PDF üretildi ama beklenen yolda yok: {pdf_path}. "
                f"stdout: {(stdout or b'').decode('utf-8', errors='replace')[:200]}"
            )

        return pdf_path.read_bytes()
