from __future__ import annotations

import json
import logging
from datetime import date, datetime
from typing import Any

logger = logging.getLogger("dscons.postgres.project_crud.mutations")


class ProjectsMutationsMixin:
    """Project creation, update, and deletion mutation operations."""

    def create_project(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Tạo dự án mới kèm khởi tạo WBS và milestones nếu có."""
        company_id = payload.get("company_id")
        project_code = payload.get("project_code")
        if not project_code:
            project_code = f"DA-{datetime.now().strftime('%y%m%d%H%M')}"

        sql_proj = """
            INSERT INTO projects (
                company_id, project_code, project_name, client_name, location,
                description, project_type, status, priority, budget_amount,
                contract_value, start_date, expected_end_date, actual_end_date,
                project_manager_id, progress_percent, notes, contract_number,
                contract_type, contract_duration_days, advance_payment_percent,
                retention_percent, contract_signing_date, contract_schedule_json
            ) VALUES (
                %(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, %(actual_end_date)s,
                %(project_manager_id)s, %(progress_percent)s, %(notes)s, %(contract_number)s,
                %(contract_type)s, %(contract_duration_days)s, %(advance_payment_percent)s,
                %(retention_percent)s, %(contract_signing_date)s, %(contract_schedule_json)s
            ) RETURNING *;
        """

        with self.get_connection() as conn:
            with conn.cursor() as cur:
                # If company_id not provided, look up the first active company
                if not company_id:
                    cur.execute("SELECT id FROM companies LIMIT 1;")
                    comp_row = cur.fetchone()
                    if comp_row:
                        company_id = comp_row["id"]
                    else:
                        cur.execute(
                            "INSERT INTO companies (company_code, legal_name, display_name) VALUES ('DSCONS', 'Công ty Cổ phần Định Sơn', 'Định Sơn Construction') RETURNING id;"
                        )
                        company_id = cur.fetchone()["id"]

                clean_payload = {
                    "company_id": company_id,
                    "project_code": project_code,
                    "project_name": payload.get("project_name", "Dự án mới"),
                    "client_name": payload.get("client_name", ""),
                    "location": payload.get("location", ""),
                    "description": payload.get("description", ""),
                    "project_type": payload.get("project_type", "Dân dụng & Hạ tầng"),
                    "status": payload.get("status", "planning"),
                    "priority": payload.get("priority", "medium"),
                    "budget_amount": payload.get("budget_amount", 0),
                    "contract_value": payload.get("contract_value", 0),
                    "start_date": payload.get("start_date") or date.today(),
                    "expected_end_date": payload.get("expected_end_date"),
                    "actual_end_date": payload.get("actual_end_date"),
                    "project_manager_id": payload.get("project_manager_id"),
                    "progress_percent": payload.get("progress_percent", 0),
                    "notes": payload.get("notes", ""),
                    "contract_number": payload.get("contract_number", ""),
                    "contract_type": payload.get("contract_type", "Trọn gói"),
                    "contract_duration_days": payload.get(
                        "contract_duration_days", 180
                    ),
                    "advance_payment_percent": payload.get(
                        "advance_payment_percent", 10.0
                    ),
                    "retention_percent": payload.get("retention_percent", 5.0),
                    "contract_signing_date": payload.get("contract_signing_date"),
                    "contract_schedule_json": json.dumps(
                        payload.get("contract_schedule_json", [])
                    ),
                }

                cur.execute(sql_proj, clean_payload)
                project = cur.fetchone()
                project_id = project["id"]

                # Insert initial WBS items if provided
                wbs_items = payload.get("wbs_items") or []
                if wbs_items:
                    self._insert_wbs_items_batch(cur, project_id, wbs_items)

                # Insert milestones if provided, or derive from phases
                milestones = payload.get("milestones") or []
                if not milestones and wbs_items:
                    phases = [w for w in wbs_items if w.get("task_type") == "phase"]
                    for idx, ph in enumerate(phases, 1):
                        milestones.append(
                            {
                                "milestone_name": f"Mốc {idx}: Hoàn thành {ph.get('task_name', '')}",
                                "target_date": ph.get("end_date"),
                                "status": "pending",
                                "sort_order": idx,
                                "description": f"Nghiệm thu chuyển bước giai đoạn {ph.get('wbs_code', '')}",
                            }
                        )

                if milestones:
                    sql_ms_ins = """
                        INSERT INTO project_milestones (
                            project_id, milestone_name, description, target_date, status, sort_order
                        ) VALUES (
                            %(project_id)s, %(milestone_name)s, %(description)s, %(target_date)s, %(status)s, %(sort_order)s
                        );
                    """
                    for ms in milestones:
                        cur.execute(
                            sql_ms_ins,
                            {
                                "project_id": project_id,
                                "milestone_name": ms.get(
                                    "milestone_name", "Mốc nghiệm thu"
                                ),
                                "description": ms.get("description", ""),
                                "target_date": ms.get("target_date"),
                                "status": ms.get("status", "pending"),
                                "sort_order": ms.get("sort_order", 1),
                            },
                        )

                conn.commit()

        return self.get_project_detail(str(project_id)) or project

    def update_project(
        self, project_id: str, updates: dict[str, Any]
    ) -> dict[str, Any]:
        """Cập nhật thông tin dự án."""
        allowed_fields = [
            "project_name",
            "client_name",
            "location",
            "description",
            "project_type",
            "status",
            "priority",
            "budget_amount",
            "contract_value",
            "start_date",
            "expected_end_date",
            "actual_end_date",
            "project_manager_id",
            "progress_percent",
            "notes",
            "contract_number",
            "contract_type",
            "contract_duration_days",
            "advance_payment_percent",
            "retention_percent",
            "contract_signing_date",
            "contract_schedule_json",
        ]

        set_clauses = []
        params: dict[str, Any] = {"id": project_id}

        for k, v in updates.items():
            if k in allowed_fields:
                set_clauses.append(f"{k} = %({k})s")
                if k == "contract_schedule_json" and not isinstance(v, str):
                    params[k] = json.dumps(v)
                else:
                    params[k] = v

        if not set_clauses:
            return self.get_project_detail(project_id) or {}

        set_clauses.append("updated_at = NOW()")
        sql = f"""
            UPDATE projects
            SET {", ".join(set_clauses)}
            WHERE id::text = %(id)s OR project_code = %(id)s
            RETURNING *;
        """

        with self.get_connection() as conn, conn.cursor() as cur:
            cur.execute(sql, params)
            conn.commit()

        return self.get_project_detail(project_id) or {}

    def delete_project(self, project_id: str) -> bool:
        """Xóa dự án và các bảng liên quan."""
        sql = "DELETE FROM projects WHERE id::text = %s OR project_code = %s;"
        with self.get_connection() as conn, conn.cursor() as cur:
            cur.execute(sql, (project_id, project_id))
            conn.commit()
            return cur.rowcount > 0
