import logging
from typing import Any

from fastapi import (
    APIRouter,
    BackgroundTasks,
    Depends,
    File,
    Form,
    HTTPException,
    UploadFile,
)

from app.modules.auth.presentation.auth import require_role
from app.core.postgres.erp_client import ErpDatabaseClient
from app.modules.core.application.document_processing_service import DocumentProcessingService
from app.modules.banking.application.unc_classifier_and_router import UncClassifierAndRouter

logger = logging.getLogger("dscons.api.erp.documents_upload")
router = APIRouter()
erp_client = ErpDatabaseClient()


@router.post("/documents/upload")
def upload_document(
    background_tasks: BackgroundTasks,
    file: UploadFile = File(...),
    project_code: str | None = Form(default=None),
    current_user: dict[str, Any] = Depends(
        require_role(["superadmin", "director", "pm", "site_engineer", "accountant"])
    ),
) -> dict[str, Any]:
    """Tải lên văn bản có sẵn, chạy nền AI phân loại và trích xuất dữ liệu."""
    try:
        doc_service = DocumentProcessingService()
        try:
            company_id, project_id = doc_service.resolve_upload_context(project_code)
        except ValueError as val_err:
            raise HTTPException(status_code=400, detail=str(val_err))

        # 3. Đọc dữ liệu file
        file_content = file.file.read()

        # 4. Lưu file qua service
        file_url, file_path, file_size, file_format, file_hash = doc_service.save_file(
            file_content, file.filename
        )

        # 4.1. Kiểm tra phát hiện trùng lặp
        duplicate_match = erp_client.check_duplicate_document(
            file_hash=file_hash,
            filename=file.filename,
            file_size_bytes=file_size,
            project_id=project_id,
        )

        # 4.2. Tự động nhận diện UNC / Sao kê ngân hàng và điều hướng vào Hot Watcher
        is_unc, detected_bank, unc_details = UncClassifierAndRouter.detect_unc_and_bank(
            filename=file.filename,
            content=file_content,
            enable_vision_ocr=False,
        )
        unc_routing_info = None
        if is_unc:
            try:
                hot_folder, hot_file_path = UncClassifierAndRouter.route_to_hot_folder(
                    file_content=file_content,
                    filename=file.filename,
                    bank_code=detected_bank,
                )
                router_svc = UncClassifierAndRouter(erp_client)
                ingest_res = router_svc.ingest_statement_file(
                    file_path=hot_file_path,
                    bank_code=detected_bank,
                    file_content=file_content,
                )
                unc_routing_info = {
                    "is_unc": True,
                    "bank_code": detected_bank,
                    "hot_folder": hot_folder,
                    "hot_file_path": hot_file_path,
                    "transactions_inserted": ingest_res.get("inserted", 0),
                    "transactions_skipped": ingest_res.get("skipped", 0),
                    "status": "routed_and_ingested"
                    if ingest_res.get("inserted", 0) > 0
                    else "routed",
                }
                logger.info(
                    "Uploaded document [%s] identified as UNC (%s) and routed to %s",
                    file.filename,
                    detected_bank,
                    hot_file_path,
                )
            except Exception as unc_err:
                logger.warning("Error routing/ingesting UNC: %s", unc_err)
                unc_routing_info = {
                    "is_unc": True,
                    "bank_code": detected_bank,
                    "error": str(unc_err),
                }

        # 5. Tạo bản ghi ban đầu ở trạng thái processing
        import uuid

        temp_code = f"TEMP-{uuid.uuid4().hex[:6].upper()}"
        clean_initial_title = DocumentProcessingService.sanitize_document_title(
            file.filename, file.filename
        )

        initial_doc_type = "UNC" if is_unc else "CV"
        initial_doc_group = "financial" if is_unc else "Văn Bản Hành Chính"
        initial_summary = (
            f"Ủy nhiệm chi / Sao kê ngân hàng {detected_bank or ''}. Đã tự động phân loại và chuyển vào Hot Watcher đối soát."
            if is_unc
            else "AI đang trích xuất dữ liệu, vui lòng đợi..."
        )

        doc_payload = {
            "company_id": company_id,
            "project_id": project_id,
            "document_code": temp_code,
            "document_title": clean_initial_title,
            "document_group": initial_doc_group,
            "document_type": initial_doc_type,
            "category": "financial" if is_unc else "incoming",
            "file_url": file_url,
            "file_hash": file_hash,
            "summary_content": initial_summary,
            "status": "processing",
        }

        doc = erp_client.create_document(doc_payload)
        doc_id = doc["id"]

        # Cập nhật thêm các cột schema-drift (như file_path, file_format, file_size_bytes, file_hash, verification_status) để đồng bộ hoàn toàn
        sync_payload = {
            "file_path": file_path,
            "file_format": file_format,
            "file_size_bytes": file_size,
            "file_hash": file_hash,
            "status": "processing",
            "verification_status": "processing",
        }
        doc = erp_client.update_document(doc_id, sync_payload)

        # 6. Giao tác vụ nền chạy AI phân loại
        background_tasks.add_task(
            doc_service.run_pipeline,
            doc_id=doc_id,
            file_path_str=file_path,
            filename=file.filename,
            file_format=file_format,
        )

        doc["unc_routing"] = unc_routing_info
        doc["is_duplicate"] = bool(duplicate_match)
        if duplicate_match:
            doc["duplicate_info"] = {
                "id": str(duplicate_match["id"]),
                "document_code": duplicate_match.get("document_code"),
                "document_title": duplicate_match.get("document_title"),
                "created_at": duplicate_match.get("created_at").isoformat()
                if duplicate_match.get("created_at")
                else None,
                "version_number": duplicate_match.get("version_number", "v1.0"),
                "duplicate_reason": duplicate_match.get("duplicate_reason"),
            }
            doc["warning_message"] = (
                f"⚠️ Cảnh báo: Văn bản vừa tải lên bị trùng lặp với văn bản đã có [{duplicate_match.get('document_code')} - {duplicate_match.get('document_title')}] ({duplicate_match.get('duplicate_reason')})."
            )
        else:
            doc["duplicate_info"] = None
            doc["warning_message"] = None

        return doc
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.post("/documents/{doc_id}/upload-version")
async def upload_document_version(
    doc_id: str,
    background_tasks: BackgroundTasks,
    file: UploadFile = File(...),
    change_summary: str | None = Form(default=None),
    signature_status: str | None = Form(default="draft"),
    current_user: dict[str, Any] = Depends(
        require_role(["superadmin", "director", "pm", "site_engineer", "accountant"])
    ),
) -> dict[str, Any]:
    """Tải lên phiên bản mới / bản sửa đổi / bản đã ký đóng dấu thay thế cho văn bản cũ."""
    try:
        parent_doc = erp_client.get_document(doc_id)
        if not parent_doc:
            raise HTTPException(status_code=404, detail="Không tìm thấy văn bản gốc.")

        # 1. Lưu file mới
        file_content = await file.read()
        doc_service = DocumentProcessingService()
        file_url, file_path, file_size, file_format, file_hash = doc_service.save_file(
            file_content, file.filename
        )

        # 2. Trích xuất text bản cũ và bản mới để chạy Diffing
        old_text = ""
        if parent_doc.get("file_path"):
            old_text = doc_service.extract_text(
                parent_doc["file_path"], parent_doc.get("file_format", "pdf")
            )
        new_text = doc_service.extract_text(file_path, file_format)

        # 3. AI Diffing (Graceful fallback)
        try:
            diff_res = await doc_service.compare_document_versions(
                old_text=old_text or parent_doc.get("summary_content", ""),
                new_text=new_text or "Nội dung phiên bản mới",
                filename_old=parent_doc.get("document_title", "bản_cũ"),
                filename_new=file.filename,
            )
        except Exception:
            diff_res = {
                "summary_of_changes": change_summary or "Tải lên bản cập nhật mới",
                "financial_impact": "Không phát hiện thay đổi",
                "legal_impact": "Chờ rà soát",
                "key_differences": [],
            }

        # 4. Tạo version mới trong database
        clean_version_title = DocumentProcessingService.sanitize_document_title(
            file.filename, file.filename
        )
        version_payload = {
            "file_url": file_url,
            "file_path": file_path,
            "file_size_bytes": file_size,
            "file_format": file_format,
            "file_hash": file_hash,
            "document_title": clean_version_title,
            "signature_status": signature_status or "draft",
            "change_summary": change_summary
            or diff_res.get("summary_of_changes", "Tải lên bản cập nhật mới"),
            "diff_analysis": diff_res,
            "status": "pending_review",
            "verification_status": "pending_review",
        }

        new_version_doc = erp_client.create_document_version(
            parent_doc_id=doc_id, payload=version_payload
        )

        # 5. Chạy AI pipeline trích xuất thêm metadata
        background_tasks.add_task(
            doc_service.run_pipeline,
            doc_id=new_version_doc["id"],
            file_path_str=file_path,
            filename=file.filename,
            file_format=file_format,
        )

        return new_version_doc
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))
