"""Graph read routes for vis-network frontend consumption."""

import logging
from typing import Any

from fastapi import APIRouter, Depends, Query
from neo4j import Session
from pydantic import BaseModel, Field

from app.core.database import get_db_session
from app.core.security import verify_supabase_jwt
from app.services.graph_service import get_subgraph_by_workspace, delete_literature_node_and_assets

logger = logging.getLogger(__name__)
router = APIRouter(tags=["Graph"])


class VisNode(BaseModel):
    """Single node in vis-network format.

    Attributes:
        id: Neo4j elementId string.
        label: Display title for the node.
        attributes: Additional node properties for detail panel.
    """

    id: str
    label: str | None = None
    attributes: dict[str, Any] = Field(default_factory=dict)


class VisEdge(BaseModel):
    """Single edge in vis-network format with canonical Neo4j data.

    Attributes:
        from_node: Source node elementId.
        to_node: Target node elementId.
        relation: Neo4j relationship type (e.g. SIMILAR_BACKGROUND).
        label: Edge reasoning text generated by LLM.
        fromTitle: Title of the source node.
        toTitle: Title of the target node.
        score: Cosine similarity score of the edge.
    """

    from_node: str = Field(alias="from")
    to_node: str = Field(alias="to")
    relation: str
    label: str | None = None
    fromTitle: str | None = None
    toTitle: str | None = None
    score: float | None = None

    model_config = {"populate_by_name": True}


class GraphResponse(BaseModel):
    """Complete graph payload for vis-network rendering.

    Attributes:
        nodes: List of graph nodes.
        edges: List of graph edges.
    """

    nodes: list[VisNode] = Field(default_factory=list)
    edges: list[VisEdge] = Field(default_factory=list)


class DeleteResponse(BaseModel):
    status: str
    message: str


@router.get(
    "/context",
    response_model=GraphResponse,
)
def get_graph_context(
    project_id: str = Query(..., description="Project identifier to scope the graph"),
    user_id: str = Depends(verify_supabase_jwt),
    session: Session = Depends(get_db_session),
) -> GraphResponse:
    """Retrieve the knowledge graph for a project in vis-network format.

    Args:
        project_id: Query parameter identifying the target project.
        user_id: Authenticated user id extracted from JWT.
        session: Neo4j session provided by dependency injection.

    Returns:
        GraphResponse: Nodes and edges formatted for vis-network rendering.
    """
    logger.info(
        "Graph context requested",
        extra={"user_id": user_id, "project_id": project_id},
    )
    data = get_subgraph_by_workspace(session, project_id, user_id)
    return GraphResponse(**data)


@router.delete(
    "/literature/{node_id}",
    response_model=DeleteResponse,
)
def delete_literature_node(
    node_id: str,
    user_id: str = Depends(verify_supabase_jwt),
    session: Session = Depends(get_db_session),
) -> DeleteResponse:
    """Atomically delete a literature node and its associated assets.

    Removes the node from Neo4j, physical PDF from Supabase Storage,
    and vector chunks from Supabase Postgres.

    Args:
        node_id: Neo4j elementId of the node to delete.
        user_id: Authenticated user id to ensure authorization.
        session: Neo4j session provided by dependency injection.

    Returns:
        DeleteResponse: Status of the deletion.

    Raises:
        HTTPException: If node is not found or user is unauthorized (404/403).
    """
    logger.info(
        "Literature deletion requested",
        extra={"user_id": user_id, "node_id": node_id},
    )
    from fastapi import HTTPException, status
    success = delete_literature_node_and_assets(session, node_id, user_id)
    if not success:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Node not found or unauthorized",
        )
    return DeleteResponse(status="success", message="Literature node and assets deleted")
