"""Entity Links plugin routes — link files to companies/contacts, reverse links."""

from __future__ import annotations

import uuid

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

from app.core.db import get_db
from app.deps import get_current_user, require_permission
from app.plugins.builtins.entity_links.models import EntityLink
from app.plugins.builtins.entity_links.schemas import EntityLinkRequest

router = APIRouter(prefix="/api/v1/entity-links", tags=["entity-links"])
contact_router = APIRouter(prefix="/api/v1/contacts", tags=["entity-links"])

VALID_ENTITY_TYPES = {"contact"}


def _parse_uuid(val: str, field: str) -> uuid.UUID:
    try:
        return uuid.UUID(val)
    except (ValueError, TypeError):
        raise HTTPException(
            400, detail={"detail": f"Invalid {field}", "code": "invalid_id"}
        ) from None


@router.post("/files/{file_id}/link", dependencies=[Depends(require_permission("entity_links:write"))])
async def link_file_to_entity(
    file_id: str,
    body: EntityLinkRequest,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Link a file to a contact."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    user_id = uuid.UUID(current_user["user_id"])
    fid = _parse_uuid(file_id, "file_id")
    entity_id = _parse_uuid(body.entity_id, "entity_id")

    if body.entity_type not in VALID_ENTITY_TYPES:
        raise HTTPException(
            400, detail={"detail": "Invalid entity_type", "code": "invalid_entity_type"}
        )

    # Check if link already exists
    existing = await db.execute(
        select(EntityLink).where(
            EntityLink.tenant_id == tenant_id,
            EntityLink.file_id == fid,
            EntityLink.entity_type == body.entity_type,
            EntityLink.entity_id == entity_id,
        )
    )
    existing_link = existing.scalar_one_or_none()
    if existing_link is not None:
        return {
            "id": str(existing_link.id),
            "file_id": str(fid),
            "entity_type": body.entity_type,
            "entity_id": str(entity_id),
            "already_linked": True,
        }

    link = EntityLink(
        tenant_id=tenant_id,
        file_id=fid,
        entity_type=body.entity_type,
        entity_id=entity_id,
        created_by=user_id,
    )
    db.add(link)
    await db.flush()
    return {
        "id": str(link.id),
        "file_id": str(link.file_id),
        "entity_type": link.entity_type,
        "entity_id": str(link.entity_id),
        "already_linked": False,
    }


@router.delete("/files/{file_id}/link", status_code=status.HTTP_204_NO_CONTENT, dependencies=[Depends(require_permission("entity_links:delete"))])
async def unlink_file_from_entity(
    file_id: str,
    body: EntityLinkRequest = Body(...),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Remove a link between a file and an entity."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    fid = _parse_uuid(file_id, "file_id")
    entity_id = _parse_uuid(body.entity_id, "entity_id")

    result = await db.execute(
        select(EntityLink).where(
            EntityLink.tenant_id == tenant_id,
            EntityLink.file_id == fid,
            EntityLink.entity_type == body.entity_type,
            EntityLink.entity_id == entity_id,
        )
    )
    link = result.scalar_one_or_none()
    if link is None:
        raise HTTPException(404, detail={"detail": "Link not found", "code": "not_found"})

    await db.delete(link)
    return Response(status_code=status.HTTP_204_NO_CONTENT)


@router.get("/files/{file_id}/links", dependencies=[Depends(require_permission("entity_links:read"))])
async def list_file_links(
    file_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """List all entities linked to a file."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    fid = _parse_uuid(file_id, "file_id")

    result = await db.execute(
        select(EntityLink).where(
            EntityLink.tenant_id == tenant_id,
            EntityLink.file_id == fid,
        )
    )
    links = result.scalars().all()
    return [
        {
            "id": str(link.id),
            "file_id": str(link.file_id),
            "entity_type": link.entity_type,
            "entity_id": str(link.entity_id),
        }
        for link in links
    ]


@contact_router.get("/{contact_id}/files", dependencies=[Depends(require_permission("entity_links:read"))])
async def list_contact_files(
    contact_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """List all files linked to a contact (reverse link)."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    cid = _parse_uuid(contact_id, "contact_id")

    result = await db.execute(
        select(EntityLink).where(
            EntityLink.tenant_id == tenant_id,
            EntityLink.entity_type == "contact",
            EntityLink.entity_id == cid,
        )
    )
    links = result.scalars().all()
    return [
        {
            "id": str(link.id),
            "file_id": str(link.file_id),
            "entity_type": link.entity_type,
            "entity_id": str(link.entity_id),
        }
        for link in links
    ]
