"""
PPM Application — Capacity Planning Service

سرویس لایه اپلیکیشن برای برنامه‌ریزی ظرفیت منابع.
"""

import logging
from typing import Optional
from uuid import UUID

from apps.core.event_bus.events import event_bus
from ...domain.entities.capacity import CapacityPlan, ResourceDemand, ResourceSupply
from ...domain.services.capacity_analyzer import CapacityAnalyzer
from ...domain.events.ppm_events import CapacityPlanCreated, CapacityBottleneckDetected
from ...infrastructure.repositories.capacity_plan_repo import DjangoCapacityPlanRepository
from ...infrastructure.repositories.resource_demand_repo import DjangoResourceDemandRepository
from ...infrastructure.repositories.resource_supply_repo import DjangoResourceSupplyRepository

logger = logging.getLogger(__name__)


class CapacityService:
    """سرویس مدیریت برنامه ظرفیت، تقاضا و عرضه منابع."""

    def __init__(self):
        self.plan_repo = DjangoCapacityPlanRepository()
        self.demand_repo = DjangoResourceDemandRepository()
        self.supply_repo = DjangoResourceSupplyRepository()
        self.analyzer = CapacityAnalyzer()

    # ─── Capacity Plan CRUD ──────────────────────────────────

    def create_plan(self, dto, tenant_id: UUID) -> CapacityPlan:
        entity = CapacityPlan(
            tenant_id=tenant_id,
            name=dto.name,
            description=dto.description,
            portfolio_id=dto.portfolio_id,
            period_start=dto.period_start,
            period_end=dto.period_end,
            is_active=dto.is_active,
            metadata=dto.metadata or {},
        )
        saved = self.plan_repo.save(entity)
        event_bus.publish(CapacityPlanCreated(
            tenant_id=tenant_id,
            capacity_plan_id=saved.id,
            name=saved.name,
        ))
        logger.info(f"CapacityPlan created: {saved.id}")
        return saved

    def get_plan(self, plan_id: UUID):
        return self.plan_repo.get_by_id(plan_id)

    def list_plans(self, **filters) -> list:
        return self.plan_repo.find(**filters)

    def update_plan(self, plan_id: UUID, data: dict):
        entity = self.plan_repo.get_by_id(plan_id)
        if not entity:
            return None
        for key, value in data.items():
            if hasattr(entity, key):
                setattr(entity, key, value)
        return self.plan_repo.save(entity)

    def delete_plan(self, plan_id: UUID) -> None:
        self.plan_repo.delete(plan_id)

    # ─── Resource Demand CRUD ────────────────────────────────

    def add_demand(self, dto, tenant_id: UUID) -> ResourceDemand:
        entity = ResourceDemand(
            tenant_id=tenant_id,
            capacity_plan_id=dto.capacity_plan_id,
            resource_type=dto.resource_type,
            project_id=dto.project_id,
            demand_hours=dto.demand_hours,
            period=dto.period,
            notes=dto.notes,
        )
        return self.demand_repo.save(entity)

    def list_demands(self, capacity_plan_id: UUID) -> list:
        return self.demand_repo.find_by_plan(capacity_plan_id)

    def delete_demand(self, demand_id: UUID) -> None:
        self.demand_repo.delete(demand_id)

    # ─── Resource Supply CRUD ────────────────────────────────

    def add_supply(self, dto, tenant_id: UUID) -> ResourceSupply:
        entity = ResourceSupply(
            tenant_id=tenant_id,
            capacity_plan_id=dto.capacity_plan_id,
            resource_type=dto.resource_type,
            available_hours=dto.available_hours,
            period=dto.period,
            notes=dto.notes,
        )
        return self.supply_repo.save(entity)

    def list_supplies(self, capacity_plan_id: UUID) -> list:
        return self.supply_repo.find_by_plan(capacity_plan_id)

    def delete_supply(self, supply_id: UUID) -> None:
        self.supply_repo.delete(supply_id)

    # ─── Analysis ────────────────────────────────────────────

    def analyze_capacity(self, capacity_plan_id: UUID):
        """تحلیل عرضه و تقاضای منابع یک برنامه ظرفیت."""
        demands = self.demand_repo.find_by_plan(capacity_plan_id)
        supplies = self.supply_repo.find_by_plan(capacity_plan_id)
        gaps = self.analyzer.calculate_demand_vs_supply(demands, supplies)
        bottlenecks = self.analyzer.identify_bottlenecks(gaps, demands)

        # Publish events for bottlenecks
        plan = self.plan_repo.get_by_id(capacity_plan_id)
        for bn in bottlenecks:
            event_bus.publish(CapacityBottleneckDetected(
                tenant_id=plan.tenant_id if plan else None,
                capacity_plan_id=capacity_plan_id,
                resource_type=bn.resource_type,
                period=bn.period,
            ))

        return {
            "gaps": gaps,
            "bottlenecks": bottlenecks,
        }
