"""
Django ORM-backed configuration storage scoped by Client.
Keeps the same interface used by existing app.config.config_storage.
"""
import copy
from typing import Dict, Optional

from app.config.config_storage import DEFAULT_GP_THRESHOLDS, DEFAULT_KPI_TARGETS
from dashboard_api.models import (
    ClientGPThreshold,
    ClientKPITargetOverride,
    ClientRevenueTarget,
)
from integrations.client_context import get_current_client


class DjangoConfigStorage:
    def _client(self):
        return get_current_client()

    def get_targets_breakevens(self) -> Dict:
        client = self._client()
        if not client:
            return {}
        out = {}
        for row in ClientRevenueTarget.objects.filter(client=client):
            key = f"{row.branch_id}_{row.company_id}"
            out[key] = {}
            if row.target is not None:
                out[key]["target"] = row.target
            if row.breakeven is not None:
                out[key]["breakeven"] = row.breakeven
        return out

    def update_target_breakeven(self, branch_id: str, company_id: int, target: Optional[int] = None, breakeven: Optional[int] = None):
        client = self._client()
        if not client:
            return
        row, _ = ClientRevenueTarget.objects.get_or_create(
            client=client,
            branch_id=branch_id,
            company_id=company_id,
        )
        if target is not None:
            row.target = target
        if breakeven is not None:
            row.breakeven = breakeven
        row.save()

    def get_gp_thresholds(self) -> Dict:
        client = self._client()
        out = copy.deepcopy(DEFAULT_GP_THRESHOLDS)
        if not client:
            return out
        for row in ClientGPThreshold.objects.filter(client=client):
            out[row.department_type] = {
                "green_min": row.green_min,
                "yellow_min": row.yellow_min,
                "yellow_max": row.yellow_max,
                "red_max": row.red_max,
            }
        return out

    def update_gp_thresholds(self, department_type: str, thresholds: Dict):
        client = self._client()
        if not client:
            return
        row, _ = ClientGPThreshold.objects.get_or_create(
            client=client,
            department_type=department_type.lower(),
            defaults={
                "green_min": thresholds["green_min"],
                "yellow_min": thresholds["yellow_min"],
                "yellow_max": thresholds["yellow_max"],
                "red_max": thresholds["red_max"],
            },
        )
        row.green_min = thresholds["green_min"]
        row.yellow_min = thresholds["yellow_min"]
        row.yellow_max = thresholds["yellow_max"]
        row.red_max = thresholds["red_max"]
        row.save()

    @staticmethod
    def _deep_merge(base: Dict, overrides: Dict) -> Dict:
        result = copy.deepcopy(base)
        for key, value in overrides.items():
            if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = DjangoConfigStorage._deep_merge(result[key], value)
            else:
                result[key] = copy.deepcopy(value)
        return result

    def get_kpi_targets(self) -> Dict:
        client = self._client()
        if not client:
            return copy.deepcopy(DEFAULT_KPI_TARGETS)
        overrides = {}
        for row in ClientKPITargetOverride.objects.filter(client=client):
            overrides.setdefault(row.branch, {}).setdefault(row.department, {}).setdefault(row.metric_key, {})
            if row.target is not None:
                overrides[row.branch][row.department][row.metric_key]["target"] = row.target
            if row.weight is not None:
                overrides[row.branch][row.department][row.metric_key]["weight"] = row.weight
        return self._deep_merge(DEFAULT_KPI_TARGETS, overrides)

    def update_kpi_targets(self, branch: str, department: str, metric_key: str, updates: Dict):
        client = self._client()
        if not client:
            return
        row, _ = ClientKPITargetOverride.objects.get_or_create(
            client=client,
            branch=branch,
            department=department,
            metric_key=metric_key,
        )
        if "target" in updates:
            row.target = updates["target"]
        if "weight" in updates:
            row.weight = updates["weight"]
        row.save()

    def update_all_kpi_targets(self, targets: Dict):
        client = self._client()
        if not client:
            return
        ClientKPITargetOverride.objects.filter(client=client).delete()
        rows = []
        for branch, depts in targets.items():
            for department, metrics in depts.items():
                for metric_key, vals in metrics.items():
                    if isinstance(vals, dict) and (vals.get("target") is not None or vals.get("weight") is not None):
                        rows.append(
                            ClientKPITargetOverride(
                                client=client,
                                branch=branch,
                                department=department,
                                metric_key=metric_key,
                                target=vals.get("target"),
                                weight=vals.get("weight"),
                            )
                        )
        if rows:
            ClientKPITargetOverride.objects.bulk_create(rows)

    def get_gp_color(self, department_name: str, gp_margin: float) -> str:
        thresholds = self.get_gp_thresholds()
        dept_lower = department_name.lower()
        if "electrical" in dept_lower or "residential" in dept_lower:
            dept_type = "electrical" if "electrical" in dept_lower else "residential"
        elif "commercial" in dept_lower:
            dept_type = "commercial"
        elif "air" in dept_lower:
            dept_type = "air"
        elif "solar" in dept_lower:
            dept_type = "solar"
        else:
            dept_type = "electrical"
        dept_thresholds = thresholds.get(dept_type, DEFAULT_GP_THRESHOLDS.get(dept_type, {}))
        if gp_margin >= dept_thresholds.get("green_min", 55.0):
            return "green"
        if dept_thresholds.get("yellow_min", 40.0) <= gp_margin < dept_thresholds.get("yellow_max", 55.0):
            return "yellow"
        return "red"
