# api/main.py
"""FastAPI application — Production Console backend.

Strangler fig: runs on :8431 alongside legacy review_server.py on :8430.
After regression test passes, swap to :8430.
"""
import asyncio
import sys
from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import RedirectResponse, FileResponse

# Ensure project root on sys.path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from . import state
from .deps import _paths_for_project
from .sse import router as sse_router
from .routes import console_router, generation_router, dailies_router
from .routes import assets_router, casting_router, files_router, manual_router
from .routes.overrides import router as overrides_router
from .routes.prompt_inspector import router as prompt_inspector_router
from .routes.reroll import router as reroll_router


def _init_project(project: str):
    """Initialize default project and ensure directories exist."""
    pp = _paths_for_project(project)
    pp["output_dir"].mkdir(parents=True, exist_ok=True)
    pp["refs_dir"].mkdir(parents=True, exist_ok=True)
    pp["plans_dir"].mkdir(parents=True, exist_ok=True)


@asynccontextmanager
async def lifespan(app):
    """Startup / shutdown hooks."""
    # Set event loop reference for SSE broadcast from background threads
    state.event_loop = asyncio.get_running_loop()

    # Auto-detect default project
    from recoil.core.paths import projects_root, ProjectPaths
    project = None
    if projects_root().exists():
        candidates = sorted([
            d.name for d in projects_root().iterdir()
            if d.is_dir() and not d.name.startswith((".", "_"))
            and ProjectPaths.from_root(d).visual_state_dir.is_dir()
        ])
        if candidates:
            project = candidates[0]
    if not project:
        project = "default"
    state.default_project = project
    _init_project(project)

    # Startup sweep: reset orphaned generating states
    try:
        from .deps import get_store
        store = get_store(project)
        if store:
            orphaned_statuses = ("previs_generating", "keyframe_generating",
                                 "video_submitted", "video_processing", "video_downloading")
            orphaned = store.get_shots_by_status(*orphaned_statuses)
            if orphaned:
                for shot in orphaned:
                    new_status = shot["status"].rsplit("_", 1)[0] + "_pending"
                    if new_status == "video_pending":
                        new_status = "previs_approved"
                    store.force_reset_status(shot["shot_id"], new_status, reason="startup orphan recovery")
                print(f"  [STARTUP] Reset {len(orphaned)} orphaned shots to pending")
    except Exception as e:
        print(f"  [STARTUP] Orphan recovery failed: {e}")

    pp = _paths_for_project(project)
    print(f"\n  FastAPI Production Console — {project}")
    print(f"  Project: {project}")
    print(f"  Bible:   {pp['bible_path']}")
    print(f"  Frames:  {pp['frames_dir']}")

    yield

    state.thread_pool.shutdown(wait=False)


app = FastAPI(lifespan=lifespan)

# ── CORS ──
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:8430", "http://127.0.0.1:8430",
        "http://localhost:8431", "http://127.0.0.1:8431",
    ],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PATCH", "OPTIONS"],
    allow_headers=["Content-Type"],
)

# ── Routers ──
app.include_router(console_router)
app.include_router(generation_router)
app.include_router(dailies_router)
app.include_router(assets_router)
app.include_router(casting_router)
app.include_router(files_router)
app.include_router(manual_router)
app.include_router(overrides_router)
app.include_router(prompt_inspector_router)
app.include_router(reroll_router)
app.include_router(sse_router)

# ── Static file serving ──
EDITORS_DIR = PROJECT_ROOT / "editors"
app.mount("/editors", StaticFiles(directory=str(EDITORS_DIR)), name="editors")

# ── Root redirect ──
@app.get("/")
def root_redirect():
    return RedirectResponse("/console")

@app.get("/console")
@app.get("/console.html")
def serve_console():
    return FileResponse(str(EDITORS_DIR / "production-console.html"))

@app.get("/review")
@app.get("/review.html")
def serve_review():
    return FileResponse(str(EDITORS_DIR / "review.html"))

@app.get("/manual")
@app.get("/manual/")
def serve_manual():
    return FileResponse(str(EDITORS_DIR / "manual-workbench.html"))

@app.get("/m")
@app.get("/m/")
def serve_mobile():
    return FileResponse(str(EDITORS_DIR / "mobile" / "mobile-console.html"))
