from __future__ import annotations

import logging
from typing import Any

logger = logging.getLogger(__name__)


class ErpDocumentAuditMixin:
    def get_audit_readiness_report(
        self, project_id: str | None = None
    ) -> dict[str, Any]:
        """Tổng hợp và chấm điểm mức độ sẵn sàng kiểm toán/quyết toán của hồ sơ công trình."""
        params: list[Any] = []
        sql = """
            SELECT 
                COUNT(*) as total_active_documents,
                COUNT(*) FILTER (WHERE signature_status = 'fully_executed') as fully_executed_count,
                COUNT(*) FILTER (WHERE signature_status = 'signed_unsigned_seal') as missing_seal_count,
                COUNT(*) FILTER (WHERE signature_status = 'draft') as draft_count,
                COUNT(*) FILTER (WHERE signature_status = 'rejected_returned') as rejected_count,
                COUNT(*) FILTER (WHERE quarantine_status = 'quarantined') as quarantined_count,
                COUNT(*) FILTER (WHERE project_stage = 'stage_06_closeout') as closeout_count,
                AVG(audit_readiness_score) as avg_score
            FROM erp_documents
            WHERE is_active_version = TRUE
        """
        if project_id:
            sql += " AND project_id = %s"
            params.append(project_id)

        with self.get_connection() as conn:
            with conn.cursor() as cur:
                cur.execute(sql, params)
                row = cur.fetchone() or {}

                total = row.get("total_active_documents") or 0
                fully = row.get("fully_executed_count") or 0
                missing_seal = row.get("missing_seal_count") or 0
                drafts = row.get("draft_count") or 0
                quarantined = row.get("quarantined_count") or 0

                # Calculate readiness percentage
                score = int(
                    row.get("avg_score")
                    or (100 if total == 0 else (fully * 100 / total))
                )

                notes = []
                if quarantined > 0:
                    notes.append(
                        f"Có {quarantined} văn bản đang bị cách ly cần thẩm duyệt giải tỏa."
                    )
                if missing_seal > 0:
                    notes.append(
                        f"Có {missing_seal} văn bản đã ký nhưng chưa đóng dấu đỏ (Cần bổ sung dấu trước khi nộp kiểm toán)."
                    )
                if drafts > 0:
                    notes.append(
                        f"Có {drafts} văn bản còn ở dạng Dự thảo / Chưa trình duyệt."
                    )
                if total == 0:
                    notes.append("Chưa có văn bản nào trong hồ sơ dự án.")

                return {
                    "total_documents": total,
                    "fully_executed_count": fully,
                    "missing_seal_count": missing_seal,
                    "draft_count": drafts,
                    "quarantined_count": quarantined,
                    "rejected_count": row.get("rejected_count") or 0,
                    "audit_readiness_score": score,
                    "readiness_status": "READY"
                    if score >= 90
                    else ("NEEDS_REVIEW" if score >= 60 else "CRITICAL"),
                    "audit_warning_notes": notes,
                }

    def delete_document(
        self, doc_id: str, delete_all_versions: bool = False
    ) -> dict[str, Any]:
        """Xóa văn bản sai hoặc trùng lặp khỏi hệ thống.

        Args:
            doc_id: ID của văn bản cần xóa
            delete_all_versions: Nếu True, xóa toàn bộ chùm phiên bản (Root + Sub-versions).
                               Nếu False, chỉ xóa phiên bản hiện tại và tự động chuyển active cho phiên bản hợp lệ gần nhất.
        """
        doc = self.get_document(doc_id)
        if not doc:
            raise ValueError(f"Không tìm thấy văn bản có ID {doc_id} để xóa.")

        root_id = doc.get("root_document_id") or doc["id"]
        deleted_count = 0
        file_paths_to_clean: list[str] = []

        with self.get_connection() as conn:
            with conn.cursor() as cur:
                if delete_all_versions:
                    # Lấy danh sách file path của toàn bộ chùm để dọn dẹp kho nếu cần
                    cur.execute(
                        "SELECT file_path FROM erp_documents WHERE root_document_id = %s OR id = %s;",
                        (root_id, root_id),
                    )
                    for r in cur.fetchall():
                        if r.get("file_path"):
                            file_paths_to_clean.append(r["file_path"])

                    cur.execute(
                        "DELETE FROM erp_documents WHERE root_document_id = %s OR id = %s;",
                        (root_id, root_id),
                    )
                    deleted_count = cur.rowcount
                else:
                    if doc.get("file_path"):
                        file_paths_to_clean.append(doc["file_path"])

                    cur.execute("DELETE FROM erp_documents WHERE id = %s;", (doc_id,))
                    deleted_count = cur.rowcount

                    # Nếu phiên bản bị xóa là bản active, tự động cập nhật bản mới nhất còn lại thành active version
                    if doc.get("is_active_version"):
                        cur.execute(
                            """
                            SELECT id FROM erp_documents
                            WHERE (root_document_id = %s OR id = %s) AND id != %s
                            ORDER BY version_index DESC, created_at DESC
                            LIMIT 1;
                        """,
                            (root_id, root_id, doc_id),
                        )
                        remaining = cur.fetchone()
                        if remaining:
                            cur.execute(
                                "UPDATE erp_documents SET is_active_version = TRUE, updated_at = NOW() WHERE id = %s;",
                                (remaining["id"],),
                            )

                conn.commit()

        # Dọn dẹp an toàn file vật lý trong secure vault nếu không còn bản ghi nào khác trỏ tới
        for fpath in file_paths_to_clean:
            try:
                from pathlib import Path

                p = Path(fpath)
                if p.exists() and "storage/secure_vault" in fpath.replace("\\", "/"):
                    with self.get_connection() as conn:
                        with conn.cursor() as cur:
                            cur.execute(
                                "SELECT count(*) FROM erp_documents WHERE file_path = %s;",
                                (fpath,),
                            )
                            usage = cur.fetchone()
                            if usage and usage["count"] == 0:
                                p.unlink(missing_ok=True)
            except Exception:
                pass

        return {
            "success": True,
            "message": f"Đã xóa thành công {deleted_count} bản ghi văn bản.",
            "deleted_id": doc_id,
            "deleted_count": deleted_count,
            "delete_all_versions": delete_all_versions,
        }

    def check_duplicate_document(
        self,
        file_hash: str | None = None,
        filename: str | None = None,
        file_size_bytes: int | None = None,
        document_code: str | None = None,
        project_id: str | None = None,
    ) -> dict[str, Any] | None:
        """Kiểm tra và phát hiện văn bản trùng lặp theo mã băm SHA-256, số hiệu hoặc tên file & dung lượng."""
        self._ensure_document_columns()
        conditions = []
        params: list[Any] = []

        # 1. Trùng lặp theo mã băm nội dung file (SHA-256) - Độ chính xác 100%
        if file_hash:
            conditions.append("d.file_hash = %s")
            params.append(file_hash)

        # 2. Trùng lặp theo số hiệu văn bản (nếu không phải mã tạm AUTO/TEMP)
        if (
            document_code
            and not document_code.startswith("TEMP-")
            and not document_code.startswith("AUTO")
        ):
            conditions.append("d.document_code = %s")
            params.append(document_code)

        # 3. Trùng lặp theo tên file gốc và kích thước nhị phân (> 0 bytes)
        if filename and file_size_bytes and file_size_bytes > 0:
            conditions.append("(d.document_title = %s AND d.file_size_bytes = %s)")
            params.extend([filename, file_size_bytes])

        if not conditions:
            return None

        sql = f"""
            SELECT d.*, p.project_name
            FROM erp_documents d
            LEFT JOIN projects p ON d.project_id = p.id
            WHERE ({" OR ".join(conditions)})
            ORDER BY d.is_active_version DESC, d.created_at DESC
            LIMIT 1;
        """

        with self.get_connection() as conn:
            with conn.cursor() as cur:
                cur.execute(sql, params)
                row = cur.fetchone()
                if row:
                    dup_reason = (
                        "Mã băm nội dung file trùng khớp 100%"
                        if file_hash and row.get("file_hash") == file_hash
                        else (
                            f"Số hiệu văn bản '{document_code}' đã tồn tại"
                            if document_code
                            and row.get("document_code") == document_code
                            else f"File '{filename}' có cùng dung lượng ({file_size_bytes} bytes) đã có trên hệ thống"
                        )
                    )
                    row["duplicate_reason"] = dup_reason
                    return row
        return None
