import uuid

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

from api.database import get_session
from api.models.task import Task
from api.models.workplan import Workplan
from api.models.workplan_dependency import WorkplanDependency
from api.schemas.workplan_dependency import WorkplanDependencyCreate, WorkplanDependencyRead
from api.routers.workstreams import _legacy_key, _meter_legacy_route

router = APIRouter(prefix="/workstreams", tags=["dependencies"])
workplan_router = APIRouter(prefix="/workplans", tags=["dependencies"])


async def _create_dependency(
    *,
    workplan_id: uuid.UUID,
    body: WorkplanDependencyCreate,
    session: AsyncSession,
) -> WorkplanDependency:
    if await session.get(Workplan, workplan_id) is None:
        raise HTTPException(status_code=404, detail="from workplan not found")

    has_workplan_target = body.to_workplan_id is not None
    has_task_target = body.to_task_id is not None
    if has_workplan_target == has_task_target:
        raise HTTPException(status_code=422, detail="provide exactly one dependency target")

    if body.to_workplan_id and await session.get(Workplan, body.to_workplan_id) is None:
        raise HTTPException(status_code=404, detail="target workplan not found")
    if body.to_task_id and await session.get(Task, body.to_task_id) is None:
        raise HTTPException(status_code=404, detail="target task not found")
    if workplan_id == body.to_workplan_id:
        raise HTTPException(status_code=422, detail="a workplan cannot depend on itself")

    dep = WorkplanDependency(
        from_workplan_id=workplan_id,
        to_workplan_id=body.to_workplan_id,
        to_task_id=body.to_task_id,
        relationship_type=body.relationship_type,
        description=body.description,
    )
    session.add(dep)
    await session.commit()
    await session.refresh(dep)
    return dep


async def _list_dependencies(
    *,
    workplan_id: uuid.UUID,
    session: AsyncSession,
) -> list[WorkplanDependency]:
    if await session.get(Workplan, workplan_id) is None:
        raise HTTPException(status_code=404, detail="workplan not found")
    rows = await session.execute(
        select(WorkplanDependency).where(
            (WorkplanDependency.from_workplan_id == workplan_id)
            | (WorkplanDependency.to_workplan_id == workplan_id)
        )
    )
    return list(rows.scalars().all())


async def _delete_dependency(
    *,
    workplan_id: uuid.UUID,
    dep_id: uuid.UUID,
    session: AsyncSession,
) -> None:
    dep = await session.get(WorkplanDependency, dep_id)
    if dep is None:
        raise HTTPException(status_code=404, detail="dependency not found")
    if dep.from_workplan_id != workplan_id:
        raise HTTPException(status_code=403, detail="dependency does not belong to this workplan")
    await session.delete(dep)
    await session.commit()


@router.post(
    "/{workstream_id}/dependencies/",
    response_model=WorkplanDependencyRead,
    status_code=status.HTTP_201_CREATED,
)
async def create_dependency(
    request: Request,
    response: Response,
    workstream_id: uuid.UUID,
    body: WorkplanDependencyCreate,
    session: AsyncSession = Depends(get_session),
) -> WorkplanDependency:
    """Record that workstream_id depends on another workplan or a task."""
    await _meter_legacy_route(
        session=session,
        request=request,
        response=response,
        interface_key=_legacy_key("POST", "/workstreams/{workstream_id}/dependencies/"),
        replacement_ref="/workplans/{workplan_id}/dependencies/",
    )
    return await _create_dependency(workplan_id=workstream_id, body=body, session=session)


@workplan_router.post(
    "/{workplan_id}/dependencies/",
    response_model=WorkplanDependencyRead,
    status_code=status.HTTP_201_CREATED,
)
async def create_workplan_dependency(
    workplan_id: uuid.UUID,
    body: WorkplanDependencyCreate,
    session: AsyncSession = Depends(get_session),
) -> WorkplanDependency:
    return await _create_dependency(workplan_id=workplan_id, body=body, session=session)


@router.get(
    "/{workstream_id}/dependencies/",
    response_model=list[WorkplanDependencyRead],
)
async def list_dependencies(
    request: Request,
    response: Response,
    workstream_id: uuid.UUID,
    session: AsyncSession = Depends(get_session),
) -> list[WorkplanDependency]:
    """Return all dependency edges touching this workplan (both directions)."""
    await _meter_legacy_route(
        session=session,
        request=request,
        response=response,
        interface_key=_legacy_key("GET", "/workstreams/{workstream_id}/dependencies/"),
        replacement_ref="/workplans/{workplan_id}/dependencies/",
    )
    return await _list_dependencies(workplan_id=workstream_id, session=session)


@workplan_router.get(
    "/{workplan_id}/dependencies/",
    response_model=list[WorkplanDependencyRead],
)
async def list_workplan_dependencies(
    workplan_id: uuid.UUID,
    session: AsyncSession = Depends(get_session),
) -> list[WorkplanDependency]:
    return await _list_dependencies(workplan_id=workplan_id, session=session)


@router.delete(
    "/{workstream_id}/dependencies/{dep_id}",
    status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_dependency(
    request: Request,
    response: Response,
    workstream_id: uuid.UUID,
    dep_id: uuid.UUID,
    session: AsyncSession = Depends(get_session),
) -> None:
    """Hard-delete a dependency edge. Removing a constraint is safe — no information is lost."""
    await _meter_legacy_route(
        session=session,
        request=request,
        response=response,
        interface_key=_legacy_key("DELETE", "/workstreams/{workstream_id}/dependencies/{dep_id}"),
        replacement_ref="/workplans/{workplan_id}/dependencies/{dep_id}",
    )
    await _delete_dependency(workplan_id=workstream_id, dep_id=dep_id, session=session)


@workplan_router.delete(
    "/{workplan_id}/dependencies/{dep_id}",
    status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_workplan_dependency(
    workplan_id: uuid.UUID,
    dep_id: uuid.UUID,
    session: AsyncSession = Depends(get_session),
) -> None:
    await _delete_dependency(workplan_id=workplan_id, dep_id=dep_id, session=session)