"""OSINT enrichment endpoints — view, review, and trigger enrichment of OSINT items linked to techniques."""

# Import UUID from uuid
from uuid import UUID

# Import APIRouter, Depends, HTTPException, Query, status from fastapi
from fastapi import APIRouter, Depends, HTTPException, Query, status

# Import BaseModel from pydantic
from pydantic import BaseModel

# Import Session from sqlalchemy.orm
from sqlalchemy.orm import Session

# Import get_db from app.database
from app.database import get_db

# Import get_current_user, require_any_role from app.dependencies.auth
from app.dependencies.auth import get_current_user, require_any_role

# Import UnitOfWork from app.domain.unit_of_work
from app.domain.unit_of_work import UnitOfWork

# Import User from app.models.user
from app.models.user import User

# Import  from app.services.osint_enrichment_service
from app.services.osint_enrichment_service import (
    enrich_technique_with_cves,
    get_osint_items_for_technique,
    get_osint_summary,
    get_technique_or_raise,
    mark_osint_reviewed,
)

# Import  from app.services.osint_enrichment_service
from app.services.osint_enrichment_service import (
    list_osint_items as service_list_osint_items,
)

# Assign router = APIRouter(prefix="/osint", tags=["osint"])
router = APIRouter(prefix="/osint", tags=["osint"])


# ── Schemas ──────────────────────────────────────────────────────────


class OsintItemOut(BaseModel):
    """Serialized OSINT item returned by the API."""

    # id: str
    id: str
    # technique_id: str
    technique_id: str
    # source_type: str
    source_type: str
    # source_url: str
    source_url: str
    # title: str
    title: str
    # description: str | None
    description: str | None
    # severity: str | None
    severity: str | None
    # discovered_at: str | None
    discovered_at: str | None
    # reviewed: bool
    reviewed: bool
    # Assign metadata_ = None
    metadata_: dict | None = None

    # Define class Config
    class Config:
        """ORM mode configuration for SQLAlchemy model mapping."""

        # Assign from_attributes = True
        from_attributes = True


# ── Endpoints ────────────────────────────────────────────────────────


@router.get("/items")
# Define function list_osint_items
def list_osint_items(
    # Entry: technique_id
    technique_id: UUID | None = Query(None),
    # Entry: source_type
    source_type: str | None = Query(None),
    # Entry: reviewed
    reviewed: bool | None = Query(None),
    # Entry: offset
    offset: int = Query(0, ge=0),
    # Entry: limit
    limit: int = Query(50, ge=1, le=200),
    # Entry: db
    db: Session = Depends(get_db),
    # Entry: user
    user: User = Depends(get_current_user),
) -> dict:
    """List OSINT items with optional filters.

    Args:
        technique_id (UUID | None): Filter by the technique's UUID.
        source_type (str | None): Filter by source type (e.g. ``nvd_cve``, ``advisory``).
        reviewed (bool | None): Filter by review status; ``None`` returns all.
        offset (int): Number of records to skip for pagination.
        limit (int): Maximum number of records to return.
        db (Session): SQLAlchemy database session.
        user (User): Authenticated user making the request.

    Returns:
        list: Serialised list of OSINT item dicts matching the filters.
    """
    # Return service_list_osint_items(
    return service_list_osint_items(
        db,
        # Keyword argument: technique_id
        technique_id=technique_id,
        # Keyword argument: source_type
        source_type=source_type,
        # Keyword argument: reviewed
        reviewed=reviewed,
        # Keyword argument: offset
        offset=offset,
        # Keyword argument: limit
        limit=limit,
    )


# Apply the @router.get decorator
@router.get("/summary")
# Define function osint_summary
def osint_summary(
    # Entry: db
    db: Session = Depends(get_db),
    # Entry: user
    user: User = Depends(get_current_user),
) -> dict:
    """Return summary statistics for OSINT items.

    Args:
        db (Session): SQLAlchemy database session.
        user (User): Authenticated user making the request.

    Returns:
        dict: Counts of total, reviewed, and unreviewed items broken down by source type.
    """
    # Return get_osint_summary(db)
    return get_osint_summary(db)


# Apply the @router.post decorator
@router.post("/items/{item_id}/review")
# Define function review_osint_item
def review_osint_item(
    # Entry: item_id
    item_id: UUID,
    # Entry: db
    db: Session = Depends(get_db),
    # Entry: user
    user: User = Depends(get_current_user),
) -> dict:
    """Mark an OSINT item as reviewed.

    Args:
        item_id (UUID): Primary key of the OSINT item to mark reviewed.
        db (Session): SQLAlchemy database session.
        user (User): Authenticated user performing the review.

    Returns:
        dict: Contains ``id`` (str) and ``reviewed`` (bool ``True``).
    """
    # Open context manager
    with UnitOfWork(db) as uow:
        # Assign item = mark_osint_reviewed(db, str(item_id))
        item = mark_osint_reviewed(db, str(item_id))
        # Check: not item
        if not item:
            # Raise HTTPException
            raise HTTPException(
                # Keyword argument: status_code
                status_code=status.HTTP_404_NOT_FOUND,
                # Keyword argument: detail
                detail="OSINT item not found",
            )
        # Call uow.commit()
        uow.commit()
    # Return {"id": str(item.id), "reviewed": True}
    return {"id": str(item.id), "reviewed": True}


# Apply the @router.post decorator
@router.post("/enrich/{technique_id}")
# Define function trigger_technique_enrichment
def trigger_technique_enrichment(
    # Entry: technique_id
    technique_id: UUID,
    # Entry: db
    db: Session = Depends(get_db),
    # Entry: user
    user: User = Depends(require_any_role("red_lead", "blue_lead")),
) -> dict:
    """Manually trigger OSINT enrichment for a single technique.

    Args:
        technique_id (UUID): Primary key of the technique to enrich.
        db (Session): SQLAlchemy database session.
        user (User): Authenticated red_lead or blue_lead requesting enrichment.

    Returns:
        dict: Contains ``technique_id`` (str), ``mitre_id`` (str), and ``new_items`` (int).
    """
    # Assign technique = get_technique_or_raise(db, technique_id)
    technique = get_technique_or_raise(db, technique_id)
    # Assign count = enrich_technique_with_cves(db, technique)
    count = enrich_technique_with_cves(db, technique)
    # Return {
    return {
        # Literal argument value
        "technique_id": str(technique.id),
        # Literal argument value
        "mitre_id": technique.mitre_id,
        # Literal argument value
        "new_items": count,
    }


# Apply the @router.get decorator
@router.get("/technique/{technique_id}")
# Define function get_technique_osint
def get_technique_osint(
    # Entry: technique_id
    technique_id: UUID,
    # Entry: source_type
    source_type: str | None = Query(None),
    # Entry: reviewed
    reviewed: bool | None = Query(None),
    # Entry: db
    db: Session = Depends(get_db),
    # Entry: user
    user: User = Depends(get_current_user),
) -> list:
    """Get all OSINT items for a specific technique.

    Args:
        technique_id (UUID): Primary key of the technique.
        source_type (str | None): Filter by source type (e.g. ``nvd_cve``).
        reviewed (bool | None): Filter by review status; ``None`` returns all.
        db (Session): SQLAlchemy database session.
        user (User): Authenticated user making the request.

    Returns:
        list: Dicts with OSINT item fields including source URL, severity, and review status.
    """
    # Assign items = get_osint_items_for_technique(
    items = get_osint_items_for_technique(
        db,
        str(technique_id),
        # Keyword argument: source_type
        source_type=source_type,
        # Keyword argument: reviewed
        reviewed=reviewed,
    )
    # Return [
    return [
        {
            # Literal argument value
            "id": str(item.id),
            # Literal argument value
            "source_type": item.source_type,
            # Literal argument value
            "source_url": item.source_url,
            # Literal argument value
            "title": item.title,
            # Literal argument value
            "description": item.description,
            # Literal argument value
            "severity": item.severity,
            # Literal argument value
            "discovered_at": item.discovered_at.isoformat() if item.discovered_at else None,
            # Literal argument value
            "reviewed": item.reviewed,
            # Literal argument value
            "metadata": item.metadata_,
        }
        for item in items
    ]
