from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import FileResponse
from pydantic import BaseModel
from common_logging import get_logger
from sqlalchemy.orm import Session

from app.api.deps import get_current_user, get_db
from app.models.knowledge_base import KnowledgeDocument
from app.models.user import User

logger = get_logger(__name__)
router = APIRouter()


class CalibrationFile(BaseModel):
    id: str
    title: str
    filename: str
    type: str
    status: str
    uploadedAt: str
    modelType: str | None = None

    class Config:
        from_attributes = True


class DocumentMetadata(BaseModel):
    documentNumber: str = ""
    validityStart: str = ""
    validityEnd: str | None = None
    issuingAuthorities: list[str] = []
    aiConfidence: float | None = None
    lastParsed: str | None = None


class DocumentChunk(BaseModel):
    id: str
    index: int
    content: str
    label: str | None = None
    pageNumber: int | None = None


class KnowledgeRelation(BaseModel):
    id: str
    type: str
    title: str
    targetId: str


STATUS_MAP = {"published": "synced", "draft": "pending", "archived": "pending"}


def _to_calibration_file(doc: KnowledgeDocument) -> dict:
    return {
        "id": str(doc.id),
        "title": doc.title,
        "filename": doc.file_path.split("/")[-1] if doc.file_path else doc.title,
        "type": doc.file_type or "sop",
        "status": STATUS_MAP.get(doc.status, "pending"),
        "uploadedAt": doc.created_at.isoformat() if doc.created_at else "",
        "modelType": doc.vector_model,
    }


def _get_doc(db: Session, file_id: str) -> KnowledgeDocument:
    doc = (
        db.query(KnowledgeDocument)
        .filter(KnowledgeDocument.id == int(file_id), not KnowledgeDocument.is_deleted)
        .first()
    )
    if not doc:
        logger.warning(f"File not found: file_id={file_id}")
        raise HTTPException(status_code=404, detail="File not found")
    return doc


@router.get("/files", response_model=list[CalibrationFile])
async def get_files(
    type: str | None = None,
    status: str | None = None,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    logger.info(f"Fetching calibration files: type={type}, status={status}, user={current_user.id}")
    query = db.query(KnowledgeDocument).filter(not KnowledgeDocument.is_deleted)
    if current_user.tenant_id:
        query = query.filter(KnowledgeDocument.tenant_id == current_user.tenant_id)
    if type:
        query = query.filter(KnowledgeDocument.file_type == type)
    files = query.all()
    logger.info(f"Found {len(files)} calibration files")
    return [_to_calibration_file(d) for d in files]


@router.get("/files/{file_id}/content")
async def get_file_content(
    file_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
    import os

    from fastapi.responses import JSONResponse

    logger.info(f"Fetching file content: file_id={file_id}, user={current_user.id}")
    doc = _get_doc(db, file_id)
    if doc.file_path and os.path.exists(doc.file_path):
        return FileResponse(doc.file_path)
    if doc.content:
        return JSONResponse(
            {"type": "text", "content": doc.content, "file_type": doc.file_type or "txt"}
        )
    logger.warning(f"No content available for file: file_id={file_id}")
    raise HTTPException(status_code=404, detail="No content available")


@router.get("/files/{file_id}/metadata", response_model=DocumentMetadata)
async def get_metadata(
    file_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
    doc = _get_doc(db, file_id)
    return DocumentMetadata(
        documentNumber=doc.source or "",
        validityStart=doc.created_at.isoformat() if doc.created_at else "",
        lastParsed=doc.updated_at.isoformat() if doc.updated_at else None,
    )


@router.get("/files/{file_id}/chunks", response_model=list[DocumentChunk])
async def get_chunks(
    file_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
    doc = _get_doc(db, file_id)
    return [
        DocumentChunk(id=str(v.id), index=v.chunk_index, content=v.chunk_text)
        for v in sorted(doc.vectors, key=lambda x: x.chunk_index)
    ]


@router.get("/files/{file_id}/relations", response_model=list[KnowledgeRelation])
async def get_relations(
    file_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
    _get_doc(db, file_id)
    return []


@router.put("/files/{file_id}/metadata")
async def update_metadata(
    file_id: str,
    metadata: DocumentMetadata,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    doc = _get_doc(db, file_id)
    doc.source = metadata.documentNumber
    doc.updated_at = datetime.utcnow()
    db.commit()
    return {"ok": True}


@router.post("/files/{file_id}/publish")
async def publish_file(
    file_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
    logger.info(f"Publishing file: file_id={file_id}, user={current_user.id}")
    doc = _get_doc(db, file_id)
    doc.status = "published"
    doc.updated_at = datetime.utcnow()
    db.commit()
    logger.info(f"File published: file_id={file_id}")
    return {"ok": True}


@router.post("/files/{file_id}/invalidate")
async def invalidate_file(
    file_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
    doc = _get_doc(db, file_id)
    doc.status = "archived"
    doc.updated_at = datetime.utcnow()
    db.commit()
    return {"ok": True}
