"""Draft template endpoints — Phase 6 post-resolve templatization flow.

Engineers who picked "Run now, templatize after resolve" on the three-option
dialog (Phase 5) generate a `draft_templates` row at decision time. After
the session resolves, the TemplatizePrompt component lets them either:
  - Accept → promotes the draft to a real `script_templates` row
  - Reject → marks the draft rejected, no library entry created

The Script Library sidebar uses the list endpoint to surface a
"X drafts ready to review" badge for the account.

See FLOWPILOT-MIGRATION.md Section 5.3.
"""
import logging
import re
from datetime import datetime, timezone
from typing import Annotated
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_current_active_user, get_db, require_engineer_or_admin
from app.models.ai_session import AISession
from app.models.draft_template import DraftTemplate
from app.models.script_template import ScriptCategory, ScriptTemplate
from app.models.user import User
from app.schemas.draft_template import (
    DraftTemplateAcceptRequest,
    DraftTemplateAcceptResponse,
    DraftTemplateListResponse,
    DraftTemplateRejectResponse,
    DraftTemplateResponse,
)

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/draft-templates", tags=["draft-templates"])


def _slugify(name: str) -> str:
    """Same slug rule as scripts.create_template — lowercase, kebab-case, ASCII."""
    return re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-")


# ── List ─────────────────────────────────────────────────────────────────

@router.get("", response_model=DraftTemplateListResponse)
async def list_drafts(
    current_user: Annotated[User, Depends(get_current_active_user)],
    db: Annotated[AsyncSession, Depends(get_db)],
    _: None = Depends(require_engineer_or_admin),
    pending_only: bool = True,
) -> DraftTemplateListResponse:
    """List drafts for the current user's account.

    Defaults to pending-only — that's what the Script Library badge counts
    and what the post-resolve TemplatizePrompt iterates over. Pass
    `pending_only=false` to include accepted/rejected for an audit view.
    """
    stmt = select(DraftTemplate).order_by(DraftTemplate.created_at.desc())
    if pending_only:
        stmt = stmt.where(DraftTemplate.status == "pending")
    result = await db.execute(stmt)
    drafts = list(result.scalars().all())
    return DraftTemplateListResponse(
        drafts=[DraftTemplateResponse.model_validate(d) for d in drafts]
    )


# ── Get one ──────────────────────────────────────────────────────────────

@router.get("/{draft_id}", response_model=DraftTemplateResponse)
async def get_draft(
    draft_id: UUID,
    current_user: Annotated[User, Depends(get_current_active_user)],
    db: Annotated[AsyncSession, Depends(get_db)],
    _: None = Depends(require_engineer_or_admin),
) -> DraftTemplateResponse:
    draft = await _load_draft_or_404(db, draft_id)
    return DraftTemplateResponse.model_validate(draft)


# ── Accept ───────────────────────────────────────────────────────────────

@router.post(
    "/{draft_id}/accept",
    response_model=DraftTemplateAcceptResponse,
    status_code=201,
)
async def accept_draft(
    draft_id: UUID,
    body: DraftTemplateAcceptRequest,
    current_user: Annotated[User, Depends(get_current_active_user)],
    db: Annotated[AsyncSession, Depends(get_db)],
    _: None = Depends(require_engineer_or_admin),
) -> DraftTemplateAcceptResponse:
    """Promote a draft to a real `script_templates` row.

    Provenance fields (`source_session_id`, `source_user_id`,
    `source_ticket_ref`) are copied so the Script Library can render the
    "generated from CW #X · resolved by Y · used N times" chip.

    On success: draft.status='accepted', draft.promoted_template_id set,
    draft.resolved_at set. The new template is owned by the engineer's team
    (matches scripts.create_template's behavior).

    Returns 409 if the draft is already accepted/rejected.
    """
    draft = await _load_draft_or_404(db, draft_id)
    if draft.status != "pending":
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Draft is already {draft.status}",
        )

    # Validate the category exists and belongs to (or is global for) this account.
    cat_result = await db.execute(
        select(ScriptCategory).where(
            ScriptCategory.id == body.category_id,
            ScriptCategory.is_active == True,  # noqa: E712
        )
    )
    if cat_result.scalar_one_or_none() is None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="category_id does not reference an active script category",
        )

    # Look up source-session ticket ref for the provenance chip. RLS makes
    # cross-account ai_session lookup impossible — the draft must belong to
    # the same account as the requesting user.
    source_session = (
        await db.execute(
            select(AISession).where(AISession.id == draft.source_session_id)
        )
    ).scalar_one_or_none()
    source_ticket_ref = (
        f"CW #{source_session.psa_ticket_id}"
        if source_session and source_session.psa_ticket_id
        else None
    )

    slug = _slugify(body.name)

    template = ScriptTemplate(
        category_id=body.category_id,
        team_id=current_user.team_id,
        account_id=current_user.account_id,
        created_by=current_user.id,
        name=body.name,
        slug=slug,
        description=body.description,
        script_body=body.edited_body or draft.script_body,
        parameters_schema=body.parameters_schema,
        # FlowPilot provenance — drives the Script Library chip.
        source_session_id=draft.source_session_id,
        source_user_id=draft.source_user_id,
        source_ticket_ref=source_ticket_ref,
    )
    db.add(template)
    await db.flush()  # populate template.id

    draft.status = "accepted"
    draft.promoted_template_id = template.id
    draft.resolved_at = datetime.now(timezone.utc)

    await db.commit()
    await db.refresh(template)

    return DraftTemplateAcceptResponse(
        draft_id=draft.id,
        promoted_template_id=template.id,
        template_slug=template.slug,
    )


# ── Reject ───────────────────────────────────────────────────────────────

@router.post("/{draft_id}/reject", response_model=DraftTemplateRejectResponse)
async def reject_draft(
    draft_id: UUID,
    current_user: Annotated[User, Depends(get_current_active_user)],
    db: Annotated[AsyncSession, Depends(get_db)],
    _: None = Depends(require_engineer_or_admin),
) -> DraftTemplateRejectResponse:
    """Mark a draft rejected.

    No template is created. The row stays for audit (so a team admin can see
    the engineer reviewed and explicitly declined). Returns 409 on a draft
    that's already accepted/rejected.
    """
    draft = await _load_draft_or_404(db, draft_id)
    if draft.status != "pending":
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Draft is already {draft.status}",
        )
    draft.status = "rejected"
    draft.resolved_at = datetime.now(timezone.utc)
    await db.commit()
    return DraftTemplateRejectResponse(draft_id=draft.id, status="rejected")


# ── Helpers ─────────────────────────────────────────────────────────────

async def _load_draft_or_404(
    db: AsyncSession, draft_id: UUID
) -> DraftTemplate:
    """RLS-scoped draft load. 404 covers missing + cross-tenant."""
    result = await db.execute(
        select(DraftTemplate).where(DraftTemplate.id == draft_id)
    )
    draft = result.scalar_one_or_none()
    if draft is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Draft template not found",
        )
    return draft
