"""Job Brief CRUD endpoints."""
from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException, Request, status
from motor.motor_asyncio import AsyncIOMotorDatabase

from ...core.authz import MembershipContext, assert_user_in_org, get_membership_context
from ...core.database import get_database
from ...core.logging import get_logger
from ...models.audit_log import AuditAction
from ...models.job_brief import (
    BriefStatus,
    JobBriefCreate,
    JobBriefResponse,
    JobBriefUpdate,
)
from ...models.organization import OrgRole
from ...services.audit_logger import audit_logger

logger = get_logger(__name__)
router = APIRouter(prefix="/briefs", tags=["briefs"])


def _doc_to_response(doc: dict) -> JobBriefResponse:
    return JobBriefResponse(
        id=str(doc["_id"]),
        organization_id=doc["organization_id"],
        project_id=doc.get("project_id"),
        title=doc["title"],
        description=doc.get("description"),
        requested_outputs=doc["requested_outputs"],
        languages=doc.get("languages", []),
        deadline=doc.get("deadline"),
        status=doc["status"],
        created_by=doc["created_by"],
        assignee_id=doc.get("assignee_id"),
        job_id=doc.get("job_id"),
        created_at=doc["created_at"].isoformat(),
        updated_at=doc["updated_at"].isoformat(),
        submitted_at=doc["submitted_at"].isoformat() if doc.get("submitted_at") else None,
        approved_by=doc.get("approved_by"),
    )


@router.get("", response_model=list[JobBriefResponse])
async def list_briefs(
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    org_ids = [m.organization_id for m in ctx.memberships] if hasattr(ctx, "memberships") else []
    if ctx.is_platform_admin:
        query: dict = {}
    elif org_ids:
        query = {"organization_id": {"$in": org_ids}}
    else:
        raise HTTPException(status_code=403, detail="No org memberships")

    cursor = db.job_briefs.find(query).sort("created_at", -1).limit(100)
    docs = await cursor.to_list(length=100)
    return [_doc_to_response(d) for d in docs]


@router.post("", response_model=JobBriefResponse, status_code=status.HTTP_201_CREATED)
async def create_brief(
    payload: JobBriefCreate,
    http_request: Request,
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    # Resolve org from project if not directly identifiable
    org_id: str | None = None
    if payload.project_id:
        project = await db.projects.find_one({"_id": payload.project_id}, {"client_id": 1})
        if project:
            org_id = project.get("client_id")
    if not org_id:
        # Use first membership org if user has only one (or admin)
        if ctx.is_platform_admin:
            raise HTTPException(status_code=400, detail="Admin must supply project_id or org_id cannot be inferred")
        memberships = [m for m in (ctx.memberships if hasattr(ctx, "memberships") else [])
                       if ctx.can_access_org(m.organization_id, OrgRole.MANAGER)]
        if len(memberships) == 1:
            org_id = memberships[0].organization_id
        else:
            raise HTTPException(status_code=400, detail="Cannot infer organization; supply project_id")

    assert_user_in_org(ctx, org_id, OrgRole.MANAGER)

    now = datetime.utcnow()
    doc = {
        "_id": f"brief_{now.strftime('%Y%m%d%H%M%S%f')}_{str(ctx.user.id)[-6:]}",
        "organization_id": org_id,
        "project_id": payload.project_id,
        "title": payload.title,
        "description": payload.description,
        "requested_outputs": payload.requested_outputs.model_dump(),
        "languages": payload.languages,
        "deadline": payload.deadline,
        "assignee_id": payload.assignee_id,
        "status": BriefStatus.DRAFT.value,
        "created_by": str(ctx.user.id),
        "job_id": None,
        "created_at": now,
        "updated_at": now,
        "submitted_at": None,
        "approved_by": None,
    }
    await db.job_briefs.insert_one(doc)
    await audit_logger.log_action(
        action=AuditAction.BRIEF_CREATE,
        description=f"Brief '{payload.title}' created",
        user=ctx.user,
        request=http_request,
        resource_type="brief",
        resource_id=str(doc["_id"]),
        details={"title": payload.title, "organization_id": org_id},
    )
    return _doc_to_response(doc)


@router.get("/{brief_id}", response_model=JobBriefResponse)
async def get_brief(
    brief_id: str,
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    doc = await db.job_briefs.find_one({"_id": brief_id})
    if not doc:
        raise HTTPException(status_code=404, detail="Brief not found")
    assert_user_in_org(ctx, doc["organization_id"], OrgRole.VIEWER)
    return _doc_to_response(doc)


@router.patch("/{brief_id}", response_model=JobBriefResponse)
async def update_brief(
    brief_id: str,
    payload: JobBriefUpdate,
    http_request: Request,
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    doc = await db.job_briefs.find_one({"_id": brief_id})
    if not doc:
        raise HTTPException(status_code=404, detail="Brief not found")
    assert_user_in_org(ctx, doc["organization_id"], OrgRole.MANAGER)
    if doc["status"] != BriefStatus.DRAFT.value:
        raise HTTPException(status_code=400, detail="Only DRAFT briefs can be updated")

    updates: dict = {"updated_at": datetime.utcnow()}
    if payload.title is not None:
        updates["title"] = payload.title
    if payload.description is not None:
        updates["description"] = payload.description
    if payload.requested_outputs is not None:
        updates["requested_outputs"] = payload.requested_outputs.model_dump()
    if payload.languages is not None:
        updates["languages"] = payload.languages
    if payload.deadline is not None:
        updates["deadline"] = payload.deadline

    result = await db.job_briefs.find_one_and_update(
        {"_id": brief_id},
        {"$set": updates},
        return_document=True,
    )
    await audit_logger.log_action(
        action=AuditAction.BRIEF_UPDATE,
        description=f"Brief '{brief_id}' updated",
        user=ctx.user,
        request=http_request,
        resource_type="brief",
        resource_id=brief_id,
        details={"fields_updated": list(updates.keys())},
    )
    return _doc_to_response(result)


@router.post("/{brief_id}/submit", response_model=JobBriefResponse)
async def submit_brief(
    brief_id: str,
    http_request: Request,
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    doc = await db.job_briefs.find_one({"_id": brief_id})
    if not doc:
        raise HTTPException(status_code=404, detail="Brief not found")
    assert_user_in_org(ctx, doc["organization_id"], OrgRole.MANAGER)
    if doc["status"] != BriefStatus.DRAFT.value:
        raise HTTPException(status_code=400, detail="Only DRAFT briefs can be submitted")

    now = datetime.utcnow()
    result = await db.job_briefs.find_one_and_update(
        {"_id": brief_id},
        {"$set": {"status": BriefStatus.SUBMITTED.value, "submitted_at": now, "updated_at": now}},
        return_document=True,
    )
    await audit_logger.log_action(
        action=AuditAction.BRIEF_SUBMIT,
        description=f"Brief '{brief_id}' submitted for review",
        user=ctx.user,
        request=http_request,
        resource_type="brief",
        resource_id=brief_id,
        details={"organization_id": result.get("organization_id")},
    )
    return _doc_to_response(result)


@router.post("/{brief_id}/approve", response_model=JobBriefResponse)
async def approve_brief(
    brief_id: str,
    http_request: Request,
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    doc = await db.job_briefs.find_one({"_id": brief_id})
    if not doc:
        raise HTTPException(status_code=404, detail="Brief not found")
    assert_user_in_org(ctx, doc["organization_id"], OrgRole.ADMIN)
    if doc["status"] != BriefStatus.SUBMITTED.value:
        raise HTTPException(status_code=400, detail="Only SUBMITTED briefs can be approved")

    now = datetime.utcnow()
    result = await db.job_briefs.find_one_and_update(
        {"_id": brief_id},
        {
            "$set": {
                "status": BriefStatus.APPROVED.value,
                "approved_by": str(ctx.user.id),
                "updated_at": now,
            }
        },
        return_document=True,
    )
    await audit_logger.log_action(
        action=AuditAction.BRIEF_APPROVE,
        description=f"Brief '{brief_id}' approved",
        user=ctx.user,
        request=http_request,
        resource_type="brief",
        resource_id=brief_id,
        details={"organization_id": result.get("organization_id")},
    )
    return _doc_to_response(result)
