"""
PPM Domain Service — Capacity Analyzer

تحلیل عرضه و تقاضای منابع.
شناسایی تنگناها و تحلیل سناریو.
"""

from dataclasses import dataclass, field
from decimal import Decimal
from typing import Dict, List, Optional
from uuid import UUID


@dataclass
class CapacityGap:
    """نتیجه تحلیل شکاف ظرفیت."""
    resource_type: str
    period: str
    demand_hours: Decimal
    supply_hours: Decimal
    gap_hours: Decimal   # negative = deficit, positive = surplus
    utilization_pct: Decimal  # demand / supply × 100


@dataclass
class Bottleneck:
    """تنگنای ظرفیت شناسایی‌شده."""
    resource_type: str
    period: str
    gap_hours: Decimal
    utilization_pct: Decimal
    affected_projects: List[UUID] = field(default_factory=list)


class CapacityAnalyzer:
    """
    سرویس دامنه — تحلیلگر ظرفیت (Stateless).

    تحلیل عرضه و تقاضا، شناسایی تنگناها
    و شبیه‌سازی سناریوهای "what-if".
    """

    @staticmethod
    def calculate_demand_vs_supply(
        demands: list,
        supplies: list,
    ) -> List[CapacityGap]:
        """
        محاسبه شکاف ظرفیت بر اساس تقاضا و عرضه.

        Returns list of CapacityGap per (resource_type, period).
        """
        # Aggregate demand by (resource_type, period)
        demand_map: Dict[tuple, Decimal] = {}
        for d in demands:
            key = (d.resource_type, d.period)
            demand_map[key] = demand_map.get(key, Decimal("0")) + d.demand_hours

        # Aggregate supply by (resource_type, period)
        supply_map: Dict[tuple, Decimal] = {}
        for s in supplies:
            key = (s.resource_type, s.period)
            supply_map[key] = supply_map.get(key, Decimal("0")) + s.available_hours

        # All unique keys
        all_keys = set(demand_map.keys()) | set(supply_map.keys())

        gaps = []
        for key in sorted(all_keys):
            resource_type, period = key
            demand_h = demand_map.get(key, Decimal("0"))
            supply_h = supply_map.get(key, Decimal("0"))
            gap_h = supply_h - demand_h
            utilization = (demand_h / supply_h * 100) if supply_h > 0 else Decimal("999.99")
            gaps.append(CapacityGap(
                resource_type=resource_type,
                period=period,
                demand_hours=demand_h,
                supply_hours=supply_h,
                gap_hours=gap_h,
                utilization_pct=round(utilization, 2),
            ))
        return gaps

    @staticmethod
    def identify_bottlenecks(
        gaps: List[CapacityGap],
        demands: list,
        threshold_pct: Decimal = Decimal("100"),
    ) -> List[Bottleneck]:
        """
        شناسایی تنگناها — مواردی که utilization بیش از threshold است.
        """
        bottlenecks = []
        for gap in gaps:
            if gap.utilization_pct >= threshold_pct:
                affected = [
                    d.project_id
                    for d in demands
                    if d.resource_type == gap.resource_type
                    and d.period == gap.period
                    and d.project_id
                ]
                bottlenecks.append(Bottleneck(
                    resource_type=gap.resource_type,
                    period=gap.period,
                    gap_hours=gap.gap_hours,
                    utilization_pct=gap.utilization_pct,
                    affected_projects=affected,
                ))
        return bottlenecks

    @staticmethod
    def what_if_scenario(
        demands: list,
        supplies: list,
        add_project_demands: Optional[list] = None,
        remove_project_ids: Optional[List[UUID]] = None,
    ) -> List[CapacityGap]:
        """
        تحلیل سناریو: اضافه/حذف پروژه‌ها و تأثیر بر ظرفیت.
        """
        # Filter out removed projects
        filtered_demands = list(demands)
        if remove_project_ids:
            filtered_demands = [
                d for d in filtered_demands
                if d.project_id not in remove_project_ids
            ]

        # Add new project demands
        if add_project_demands:
            filtered_demands.extend(add_project_demands)

        return CapacityAnalyzer.calculate_demand_vs_supply(
            filtered_demands, supplies,
        )
