from __future__ import annotations

import json
import logging
from typing import Any

logger = logging.getLogger(__name__)


class ErpProjectMixin:
    def list_projects(self, status: str | None = None) -> list[dict[str, Any]]:
        """Lấy danh sách tất cả các dự án thi công kèm bộ lọc trạng thái."""
        sql = """
            SELECT p.*, c.legal_name as company_name, emp.full_name as pm_name
            FROM projects p
            JOIN companies c ON p.company_id = c.id
            LEFT JOIN employees emp ON p.project_manager_id = emp.id
            WHERE 1=1
        """
        params: list[Any] = []
        if status and status != "all":
            sql += " AND p.status = %s"
            params.append(status)
        sql += " ORDER BY p.created_at DESC;"

        with self.get_connection() as conn, conn.cursor() as cur:
            cur.execute(sql, params)
            return cur.fetchall()

    def get_project(self, project_id_or_code: str) -> dict[str, Any] | None:
        """Lấy thông tin chi tiết của một dự án theo ID hoặc Mã dự án."""
        sql = """
            SELECT p.*, c.legal_name as company_name, emp.full_name as pm_name
            FROM projects p
            JOIN companies c ON p.company_id = c.id
            LEFT JOIN employees emp ON p.project_manager_id = emp.id
            WHERE p.id::text = %s OR p.project_code = %s;
        """
        with self.get_connection() as conn, conn.cursor() as cur:
            cur.execute(sql, (project_id_or_code, project_id_or_code))
            return cur.fetchone()

    def create_project(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Tạo mới hoặc cập nhật dự án thi công trong cơ sở dữ liệu."""
        import uuid

        project_id = payload.get("id") or str(uuid.uuid4())
        company_id = payload.get("company_id") or "0753d827-90e1-4894-9c16-266ca572c5eb"
        project_code = payload.get("project_code")
        if not project_code:
            project_code = f"DA-{datetime.now().year}-{uuid.uuid4().hex[:6].upper()}"

        sql = """
            INSERT INTO projects (
                id, company_id, project_code, project_name, client_name,
                location, description, project_type, status, priority,
                budget_amount, contract_value, start_date, expected_end_date,
                contract_duration_days, contract_type, notes,
                contract_schedule_json, created_at, updated_at
            ) VALUES (
                %(id)s, %(company_id)s, %(project_code)s, %(project_name)s, %(client_name)s,
                %(location)s, %(description)s, %(project_type)s, %(status)s, %(priority)s,
                %(budget_amount)s, %(contract_value)s, %(start_date)s, %(expected_end_date)s,
                %(contract_duration_days)s, %(contract_type)s, %(notes)s,
                %(contract_schedule_json)s, NOW(), NOW()
            )
            ON CONFLICT (project_code) DO UPDATE SET
                project_name = EXCLUDED.project_name,
                client_name = EXCLUDED.client_name,
                location = EXCLUDED.location,
                description = EXCLUDED.description,
                project_type = EXCLUDED.project_type,
                status = EXCLUDED.status,
                budget_amount = EXCLUDED.budget_amount,
                contract_value = EXCLUDED.contract_value,
                contract_duration_days = EXCLUDED.contract_duration_days,
                notes = EXCLUDED.notes,
                updated_at = NOW()
            RETURNING *;
        """
        insert_data = {
            "id": project_id,
            "company_id": company_id,
            "project_code": project_code,
            "project_name": payload.get("project_name") or "Dự án mới",
            "client_name": payload.get("client_name") or "Chủ đầu tư",
            "location": payload.get("location") or "TP Hải Phòng",
            "description": payload.get("description") or "",
            "project_type": payload.get("project_type") or "Thủy lợi",
            "status": payload.get("status") or "bidding",
            "priority": payload.get("priority") or "high",
            "budget_amount": payload.get("budget_amount")
            or payload.get("contract_value")
            or 0,
            "contract_value": payload.get("contract_value")
            or payload.get("budget_amount")
            or 0,
            "start_date": payload.get("start_date"),
            "expected_end_date": payload.get("expected_end_date"),
            "contract_duration_days": payload.get("contract_duration_days") or 180,
            "contract_type": payload.get("contract_type") or "Trọn gói",
            "notes": payload.get("notes") or "",
            "contract_schedule_json": json.dumps(
                payload.get("contract_schedule_json") or []
            ),
        }
        with self.get_connection() as conn, conn.cursor() as cur:
            cur.execute(sql, insert_data)
            conn.commit()
            return cur.fetchone()

    def create_project_from_document(
        self, doc_id: str, custom_payload: dict[str, Any] | None = None
    ) -> dict[str, Any]:
        """Tự động khởi tạo hoặc liên kết Dự án Đấu Thầu từ một Văn Bản (TBMT/QĐ/HĐ)."""
        doc = self.get_document(doc_id)
        if not doc:
            raise ValueError(f"Không tìm thấy văn bản id={doc_id}")

        custom = custom_payload or {}

        # 1. Trích xuất metadata dự án từ văn bản
        doc_code = doc.get("document_code") or ""
        doc_title = doc.get("document_title") or ""
        summary = doc.get("summary_content") or ""
        issuer = (
            doc.get("issuer_name")
            or doc.get("partner_name")
            or "Trung tâm Dịch vụ sự nghiệp công xã Kiến Minh"
        )

        import re
        import unicodedata

        def slugify_code(text: str) -> str:
            text = (
                unicodedata.normalize("NFKD", str(text))
                .encode("ascii", "ignore")
                .decode("utf-8")
            )
            text = re.sub(r"[^\w\s-]", "", text).strip().upper()
            return re.sub(r"[-\s]+", "-", text)

        # Xử lý tên dự án
        project_name = custom.get("project_name")
        if not project_name:
            match_da = re.search(r"[Dd]ự\s*án\s*([^,.\n()]+)", doc_title)
            if match_da:
                project_name = f"Dự án {match_da.group(1).strip()}"
            else:
                project_name = doc_title.replace("Thông báo mời thầu - ", "").replace(
                    "Thông báo mời thầu ", ""
                )

        # Xử lý mã dự án
        project_code = custom.get("project_code")
        if not project_code:
            if doc_code and not doc_code.startswith("TEMP-"):
                clean_dc = slugify_code(doc_code)
                project_code = f"DA-{clean_dc}"
            else:
                slug_title = slugify_code(project_name)[:16].rstrip("-")
                project_code = f"DA-2026-{slug_title}"

        # 2. Kiểm tra xem dự án đã tồn tại chưa (Idempotency)
        existing_proj = self.get_project(project_code)
        if not existing_proj:
            with self.get_connection() as conn:
                with conn.cursor() as cur:
                    cur.execute(
                        "SELECT * FROM projects WHERE project_name = %s LIMIT 1;",
                        (project_name,),
                    )
                    existing_proj = cur.fetchone()

        if existing_proj:
            project_id = str(existing_proj["id"])
            created_new = False
            final_project = existing_proj
        else:
            new_proj_payload = {
                "company_id": doc.get("company_id")
                or "0753d827-90e1-4894-9c16-266ca572c5eb",
                "project_code": project_code,
                "project_name": project_name,
                "client_name": custom.get("client_name") or issuer,
                "location": custom.get("location") or "TP Hải Phòng",
                "description": custom.get("description")
                or f"Khởi tạo từ văn bản {doc_code}: {doc_title}",
                "project_type": custom.get("project_type")
                or (
                    "Thủy lợi"
                    if "cống" in project_name.lower() or "kênh" in project_name.lower()
                    else "Hạ tầng kỹ thuật"
                ),
                "status": custom.get("status") or "bidding",
                "priority": custom.get("priority") or "high",
                "budget_amount": custom.get("budget_amount") or 95000000,
                "contract_value": custom.get("contract_value") or 95000000,
                "contract_duration_days": custom.get("contract_duration_days") or 270,
                "contract_type": custom.get("contract_type") or "Trọn gói",
                "notes": custom.get("notes")
                or f"Mã TBMT: {doc_code}. Tóm tắt: {summary[:300]}",
            }
            final_project = self.create_project(new_proj_payload)
            project_id = str(final_project["id"])
            created_new = True

        # 3. Gắn project_id vào văn bản và tất cả các phiên bản của nó
        root_id = doc.get("root_document_id") or doc["id"]
        with self.get_connection() as conn:
            with conn.cursor() as cur:
                cur.execute(
                    """
                    UPDATE erp_documents 
                    SET project_id = %s, project_stage = 'stage_01_initiation', updated_at = NOW() 
                    WHERE root_document_id = %s OR id = %s;
                """,
                    (project_id, root_id, root_id),
                )
                conn.commit()

        return {
            "created_new": created_new,
            "project": final_project,
            "document_id": doc["id"],
            "project_id": project_id,
            "message": f"{'Đã tự động khởi tạo dự án mới' if created_new else 'Đã liên kết vào dự án hiện có'}: {final_project.get('project_name')} ({final_project.get('project_code')})",
        }
