# -*- coding: utf-8 -*-
"""generator/output 스캔 → content 테이블 upsert.

디스크의 완성 mp4 와 DB 를 잇는다. 시작 시 + 잡 완료 시 호출.
"""
import re
import shutil
from pathlib import Path

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from . import blob_client
from .config import OUTPUT_DIR, ENGINE_SCENARIO
from .database import SessionLocal
from .models import Content

_TITLE_RE = re.compile(r"\[제목\]\s*(.+)")


def _cleanup_dir(job_dir: Path) -> None:
    """블롭 업로드·DB 커밋 성공한 job 폴더의 로컬 원본 제거(디스크 절약).

    안전장치: 반드시 OUTPUT_DIR 하위 경로일 때만 삭제.
    """
    try:
        job_dir = job_dir.resolve()
        if OUTPUT_DIR.resolve() in job_dir.parents and job_dir.is_dir():
            shutil.rmtree(job_dir, ignore_errors=True)
    except Exception as e:
        print(f"[cleanup] skip {job_dir}: {type(e).__name__}: {e}")


def _title(job_dir) -> str:
    txt = job_dir / "narration.txt"
    if txt.exists():
        for line in txt.read_text(encoding="utf-8", errors="ignore").splitlines():
            m = _TITLE_RE.match(line.strip())
            if m:
                return m.group(1).strip()
    return job_dir.name


def _scan() -> list[dict]:
    rows = []
    if not OUTPUT_DIR.is_dir():
        return rows
    for engine, sc in ENGINE_SCENARIO.items():
        d = OUTPUT_DIR / engine
        if not d.is_dir():
            continue
        for job in d.iterdir():
            if not job.is_dir():
                continue
            mp4s = sorted(job.glob("*.mp4"))
            if not mp4s:
                continue
            rel = mp4s[0].relative_to(OUTPUT_DIR).as_posix()
            rows.append({
                "id": job.name, "sc": sc, "title": _title(job),
                "mp4": mp4s[0], "local_url": f"/videos/{rel}",
            })
    return rows


async def sync_output(session: AsyncSession | None = None, owner_uuid: str | None = None) -> int:
    """새 output 폴더를 content 로 삽입. 삽입 개수 반환."""
    own = session is None
    session = session or SessionLocal()
    try:
        existing = set((await session.execute(select(Content.id))).scalars().all())
        added = 0
        uploaded_dirs: list = []           # 블롭 업로드 성공한 job 폴더 → 커밋 후 정리
        for r in _scan():
            if r["id"] in existing:
                continue
            # Azure Blob 활성 시 mp4 업로드 → 공개 URL 저장, 실패/비활성 시 로컬 /videos/ URL
            video = r["local_url"]
            if blob_client.enabled():
                url = await blob_client.upload_video(r["mp4"], owner_uuid, r["id"])
                if url:
                    video = url
                    uploaded_dirs.append(r["mp4"].parent)
            session.add(Content(
                id=r["id"], scenario=r["sc"], title=r["title"], video=video,
                owner_uuid=owner_uuid,
            ))
            added += 1
        if added:
            await session.commit()
        # 커밋 성공 후에만 로컬 원본 삭제(블롭이 진실의 원천). 실패분은 /videos fallback 위해 유지.
        for d in uploaded_dirs:
            _cleanup_dir(d)
        return added
    finally:
        if own:
            await session.close()
