"""Previews domain - FastAPI router."""
from __future__ import annotations
from typing import Optional
from uuid import UUID

from fastapi import APIRouter, Depends, Path, Query, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession

from src.core.database import get_db
from src.core.dependencies import (
    add_deprecation_header,
    get_productive_access_policy,
    require_active_billing_for_preview,
    require_active_billing_for_project,
)
from src.core.exceptions import NotFoundError
from src.domain.billing.productive_access_policy import ProductiveAccessPolicy
from src.domain.projects.repository import ProjectRepository
from src.domain.auth.models import User
from src.domain.auth.router import get_current_user
from src.domain.previews.repository import PreviewRepository, RoutesManifestRepository
from src.domain.previews.schemas import PreviewCreate, PreviewResponse
from src.domain.previews.service import PreviewService

router = APIRouter(tags=["previews"])


async def get_preview_service(db: AsyncSession = Depends(get_db)) -> PreviewService:
    return PreviewService(
        preview_repo=PreviewRepository(db),
        manifest_repo=RoutesManifestRepository(db),
    )


@router.post("/api/projects/{project}/previews", response_model=PreviewResponse)
async def create_preview(
    body: PreviewCreate,
    project: UUID = Depends(require_active_billing_for_project),
    user: User = Depends(get_current_user),
    service: PreviewService = Depends(get_preview_service),
):
    pe = await service.create_preview(project, body.revision_id)
    from src.workers.enqueue import enqueue_provision_preview_for_revision
    await enqueue_provision_preview_for_revision(
        str(pe.id), str(project), str(body.revision_id)
    )
    return PreviewResponse.model_validate(pe)


@router.get("/api/projects/{project}/previews", response_model=list[PreviewResponse])
async def list_previews(
    project: UUID = Depends(require_active_billing_for_project),
    user: User = Depends(get_current_user),
    service: PreviewService = Depends(get_preview_service),
):
    previews = await service.list_previews(project)
    return [PreviewResponse.model_validate(p) for p in previews]


@router.get(
    "/api/previews/{preview}",
    response_model=PreviewResponse,
    deprecated=True,
    summary="Deprecated: use GET /api/projects/{project_id}/previews",
)
async def get_preview(
    response: Response,
    preview: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: PreviewService = Depends(get_preview_service),
    db: AsyncSession = Depends(get_db),
    policy: ProductiveAccessPolicy = Depends(get_productive_access_policy),
):
    add_deprecation_header(response, "GET /api/projects/{project_id}/previews")
    pe = await service.get_preview(preview)
    proj = await ProjectRepository(db).get_by_id(pe.project_id)
    if not proj:
        raise NotFoundError("Project not found")
    await policy.require_for_workspace(proj.workspace_id, user.id)
    return PreviewResponse.model_validate(pe)


@router.delete(
    "/api/previews/{preview}",
    deprecated=True,
    summary="Deprecated: use DELETE /api/projects/{project_id}/previews/{preview}",
)
async def delete_preview(
    response: Response,
    preview: UUID = Depends(require_active_billing_for_preview),
    user: User = Depends(get_current_user),
    service: PreviewService = Depends(get_preview_service),
):
    add_deprecation_header(response, "DELETE /api/projects/{project_id}/previews/{preview}")
    await service.stop_preview(preview)
    return {"message": "Preview stopped"}


@router.post("/api/projects/{project}/visual-edit/start")
async def visual_edit_start(
    request: Request,
    project: UUID = Depends(require_active_billing_for_project),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Signal that the user is entering Visual Edit mode.

    Returns the current preview URL with ?__p2hs_ve=<dashboard_origin> so the CF
    dispatcher Worker knows which dashboard to load the visual-edit script from.
    """
    from src.config import get_settings
    from src.domain.previews.repository import PreviewRepository
    from src.domain.projects.repository import ProjectRepository

    project_row = await ProjectRepository(db).get_by_id(project)
    if not project_row:
        raise NotFoundError("Project not found")

    preview = None
    if project_row.active_preview_id:
        preview = await PreviewRepository(db).get_by_id(project_row.active_preview_id)

    # Resolve dashboard origin from the request Origin header, validated against whitelist
    settings = get_settings()
    request_origin = request.headers.get("origin", "").rstrip("/")
    allowed = {settings.app_url.rstrip("/")} | {
        u.strip().rstrip("/") for u in settings.app_url_whitelist.split(",") if u.strip()
    }
    dashboard_origin = request_origin if request_origin in allowed else settings.app_url.rstrip("/")

    base_url = preview.base_url if preview else None
    ve_url = f"{base_url}?__p2hs_ve={dashboard_origin}" if base_url else None
    return {
        "mode": "visual_edit",
        "preview_url": ve_url,
    }


@router.post("/api/projects/{project}/visual-edit/stop")
async def visual_edit_stop(
    project: UUID = Depends(require_active_billing_for_project),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Signal that the user is exiting Visual Edit mode.

    Returns the current (non-annotated) preview URL so the frontend can restore
    the normal preview iframe.
    """
    from src.domain.previews.repository import PreviewRepository
    from src.domain.projects.repository import ProjectRepository

    project_row = await ProjectRepository(db).get_by_id(project)
    if not project_row:
        raise NotFoundError("Project not found")

    preview = None
    if project_row.active_preview_id:
        preview = await PreviewRepository(db).get_by_id(project_row.active_preview_id)

    base_url = preview.base_url if preview else None
    clear_url = f"{base_url}?__p2hs_ve=0" if base_url else None
    return {
        "mode": "agent",
        "preview_url": clear_url,
    }


@router.get("/api/projects/{project}/routes-manifest")
async def get_routes_manifest(
    project: UUID = Depends(require_active_billing_for_project),
    revision: Optional[UUID] = Query(None),
    user: User = Depends(get_current_user),
    service: PreviewService = Depends(get_preview_service),
):
    return await service.get_routes_manifest(project, revision)
