from typing import Any

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from app.api.deps import get_db
from app.api.permissions import require_update
from app.crud.metadata import document_metadata_value, metadata_field
from app.models import KnowledgeDocument, User
from app.schemas.metadata import (
    DocumentMetadataResponse,
    DocumentMetadataUpdate,
    DocumentMetadataValueResponse,
)
from common_logging import get_logger

logger = get_logger(__name__)

router = APIRouter(tags=["document-metadata"])


def check_document_access(db: Session, document_id: int, current_user: User) -> KnowledgeDocument:
    doc = db.query(KnowledgeDocument).filter(KnowledgeDocument.id == document_id).first()
    if not doc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")
    if current_user.role == "customer_user" and doc.author_id != current_user.id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="No permission to access this document"
        )
    return doc


@router.get("/documents/{document_id}/metadata", response_model=DocumentMetadataResponse)
def get_document_metadata(
    document_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_update("knowledge_bases")),
):
    doc = check_document_access(db, document_id, current_user)
    if not doc.category_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="Document must belong to a category"
        )
    from app.models import KnowledgeCategory

    category = db.query(KnowledgeCategory).filter(KnowledgeCategory.id == doc.category_id).first()
    if not category or not category.knowledge_base_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Document category must belong to a knowledge base",
        )
    metadata_list = []
    from app.models import User

    author = db.query(User).filter(User.id == doc.author_id).first()
    system_fields = [
        DocumentMetadataValueResponse(
            field_id=0,
            field_name="Document Name",
            field_key="document_name",
            field_type="text",
            field_options=None,
            value=doc.title,
            is_system=True,
            is_readonly=True,
        ),
        DocumentMetadataValueResponse(
            field_id=0,
            field_name="Uploader",
            field_key="uploader",
            field_type="text",
            field_options=None,
            value=author.name if author else "Unknown",
            is_system=True,
            is_readonly=True,
        ),
        DocumentMetadataValueResponse(
            field_id=0,
            field_name="Upload Date",
            field_key="upload_date",
            field_type="date",
            field_options=None,
            value=doc.created_at.strftime("%Y-%m-%d") if doc.created_at else None,
            is_system=True,
            is_readonly=True,
        ),
        DocumentMetadataValueResponse(
            field_id=0,
            field_name="Last Update Date",
            field_key="last_update_date",
            field_type="date",
            field_options=None,
            value=doc.updated_at.strftime("%Y-%m-%d") if doc.updated_at else None,
            is_system=True,
            is_readonly=True,
        ),
        DocumentMetadataValueResponse(
            field_id=0,
            field_name="Source",
            field_key="source",
            field_type="text",
            field_options=None,
            value=doc.source,
            is_system=True,
            is_readonly=True,
        ),
    ]
    metadata_list.extend(system_fields)
    fields = metadata_field.get_by_knowledge_base(db, knowledge_base_id=category.knowledge_base_id)
    values = document_metadata_value.get_by_document(db, document_id=document_id)
    value_map = {v.field_id: v.value for v in values}
    for field in fields:
        metadata_list.append(
            DocumentMetadataValueResponse(
                field_id=field.id,
                field_name=field.field_name,
                field_key=field.field_key,
                field_type=field.field_type,
                field_options=field.field_options,
                value=value_map.get(field.id),
                is_system=False,
                is_readonly=False,
            )
        )
    return DocumentMetadataResponse(document_id=document_id, metadata=metadata_list)


@router.put("/documents/{document_id}/metadata", response_model=DocumentMetadataResponse)
def update_document_metadata(
    document_id: int,
    metadata_in: DocumentMetadataUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_update("knowledge_bases")),
):
    doc = check_document_access(db, document_id, current_user)
    if not doc.category_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="Document must belong to a category"
        )
    from app.models import KnowledgeCategory

    category = db.query(KnowledgeCategory).filter(KnowledgeCategory.id == doc.category_id).first()
    if not category or not category.knowledge_base_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Document category must belong to a knowledge base",
        )
    fields = metadata_field.get_by_knowledge_base(db, knowledge_base_id=category.knowledge_base_id)
    field_map = {f.field_key: f for f in fields}
    metadata_by_id: dict[int, Any] = {}
    for field_key, value in metadata_in.metadata.items():
        if field_key not in field_map:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unknown field key: {field_key}"
            )
        field = field_map[field_key]
        if value is None or value == "":
            metadata_by_id[field.id] = None
        elif field.field_type == "multiselect" and isinstance(value, list):
            import json

            metadata_by_id[field.id] = json.dumps(value)
        else:
            metadata_by_id[field.id] = str(value)
    document_metadata_value.batch_update_document_metadata(
        db, document_id=document_id, metadata=metadata_by_id
    )
    return get_document_metadata(document_id, db, current_user)


@router.delete(
    "/documents/{document_id}/metadata/{field_id}", status_code=status.HTTP_204_NO_CONTENT
)
def delete_document_metadata_value(
    document_id: int,
    field_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_update("knowledge_bases")),
):
    check_document_access(db, document_id, current_user)
    field = metadata_field.get(db, id=field_id)
    if not field:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Metadata field not found"
        )
    deleted = document_metadata_value.delete_by_document_and_field(
        db, document_id=document_id, field_id=field_id
    )
    if not deleted:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Metadata value not found"
        )
    return None
