# -*- coding: utf-8 -*-
"""썰박스 생성 잡 매니저 (subprocess → 내장 generator 엔진).

편당 2~4분·과금이 크므로 동시 실행 제한. stdout 진행 마커([1/4]…, "완성: ...mp4")를 파싱.
DB 작업은 하지 않는다 — 완료 후 처리(content 삽입·크레딧 차감)는 잡 상태 조회 엔드포인트가 1회 수행.
"""
import os
import re
import subprocess
import sys
import threading
import uuid
from collections import deque
from datetime import datetime

from .config import GENERATOR_DIR, SCENARIO_ENGINE, GEMINI_API_KEY, settings

_jobs: dict[str, dict] = {}
_queue: deque[str] = deque()
_lock = threading.Lock()
_running = 0

_STEP_RE = re.compile(r"\[(\d)\s*/\s*4\]")
_DONE_RE = re.compile(r"완성[:：]\s*(.+\.mp4)")
STEP_NAMES = ["대본 생성", "스토리보드", "이미지·음성", "영상 합성"]


def create_job(scenario: str, input_text: str, scenes: int, seconds: int, owner_uuid: str | None) -> dict:
    jid = uuid.uuid4().hex[:12]
    _jobs[jid] = {
        "id": jid, "scenario": scenario, "input": input_text,
        "scenes": scenes, "seconds": seconds, "owner_uuid": owner_uuid,
        "status": "queued", "step": 0, "log": [], "output": None, "error": None,
        "finalized": False, "created": datetime.now().isoformat(timespec="seconds"),
    }
    with _lock:
        _queue.append(jid)
    _pump()
    return _jobs[jid]


def get_job(jid: str) -> dict | None:
    return _jobs.get(jid)


def _pump():
    global _running
    with _lock:
        while _queue and _running < settings.MAX_CONCURRENT_JOBS:
            jid = _queue.popleft()
            _running += 1
            threading.Thread(target=_run, args=(jid,), daemon=True).start()


def _run(jid: str):
    global _running
    job = _jobs[jid]
    try:
        engine = SCENARIO_ENGINE[job["scenario"]]
        engine_dir = GENERATOR_DIR / engine
        main_py = engine_dir / "main.py"
        if not main_py.exists():
            raise FileNotFoundError(f"generator not found: {main_py}")

        cmd = [sys.executable, "-u", str(main_py), job["input"],
               "--scenes", str(job["scenes"]), "--seconds", str(job["seconds"])]
        env = dict(os.environ)
        env["PYTHONIOENCODING"] = "utf-8"
        if GEMINI_API_KEY:
            env["GEMINI_API_KEY"] = GEMINI_API_KEY

        job["status"] = "running"
        p = subprocess.Popen(
            cmd, cwd=str(engine_dir), env=env,
            stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
            text=True, encoding="utf-8", errors="replace", bufsize=1,
        )
        for line in p.stdout:
            line = line.rstrip()
            if not line:
                continue
            job["log"].append(line)
            if len(job["log"]) > 300:
                del job["log"][:-300]
            m = _STEP_RE.search(line)
            if m:
                job["step"] = int(m.group(1))
            d = _DONE_RE.search(line)
            if d:
                job["output"] = d.group(1).strip()
        code = p.wait()
        if code == 0:
            job["status"] = "done"; job["step"] = 4
        else:
            job["status"] = "error"; job["error"] = f"생성 프로세스 종료코드 {code}"
    except Exception as e:
        job["status"] = "error"; job["error"] = f"{type(e).__name__}: {e}"
    finally:
        with _lock:
            _running -= 1
        _pump()
