"""
PPM Application — Dependency Service

سرویس اپلیکیشن برای مدیریت وابستگی‌های بین پروژه‌ای.
"""

from typing import List, Optional
from uuid import UUID

from ..dtos.ppm_dtos import (
    CrossProjectDependencyCreateDTO,
    CrossProjectDependencyResponseDTO,
    CircularDependencyDTO,
    CriticalChainLinkDTO,
    ImpactResultDTO,
)
from ...domain.entities.dependency import CrossProjectDependency
from ...domain.services.dependency_analyzer import DependencyAnalyzer
from ...domain.events.ppm_events import (
    DependencyCreated,
    DependencyResolved,
    CircularDependencyDetected,
)
from ...infrastructure.repositories.cross_project_dependency_repo import (
    DjangoCrossProjectDependencyRepository,
)
from apps.core.event_bus.events import event_bus


class DependencyService:
    """
    سرویس اپلیکیشن — مدیریت وابستگی‌های بین پروژه‌ای.

    عملیات CRUD + تحلیل وابستگی (حلقوی، زنجیره بحرانی، تحلیل اثر).
    """

    def __init__(self):
        self._repo = DjangoCrossProjectDependencyRepository()
        self._analyzer = DependencyAnalyzer()

    # ── CRUD ──

    def create_dependency(
        self,
        dto: CrossProjectDependencyCreateDTO,
        tenant_id: UUID,
    ) -> CrossProjectDependencyResponseDTO:
        entity = CrossProjectDependency(
            tenant_id=tenant_id,
            predecessor_project_id=dto.predecessor_project_id,
            successor_project_id=dto.successor_project_id,
            predecessor_milestone_id=dto.predecessor_milestone_id,
            successor_milestone_id=dto.successor_milestone_id,
            dependency_type=dto.dependency_type,
            lag_days=dto.lag_days,
            impact_description=dto.impact_description,
            metadata=dto.metadata or {},
        )
        saved = self._repo.save(entity)

        event_bus.publish(DependencyCreated(
            tenant_id=tenant_id,
            dependency_id=saved.id,
            predecessor_project_id=saved.predecessor_project_id,
            successor_project_id=saved.successor_project_id,
            dependency_type=saved.dependency_type,
        ))

        return self._to_response(saved)

    def get_dependency(self, dependency_id: UUID) -> Optional[CrossProjectDependencyResponseDTO]:
        entity = self._repo.get_by_id(dependency_id)
        if entity is None:
            return None
        return self._to_response(entity)

    def list_dependencies(self, **filters) -> List[CrossProjectDependencyResponseDTO]:
        entities = self._repo.find(**filters)
        return [self._to_response(e) for e in entities]

    def list_by_project(self, project_id: UUID) -> List[CrossProjectDependencyResponseDTO]:
        entities = self._repo.find_by_project(project_id)
        return [self._to_response(e) for e in entities]

    def resolve_dependency(self, dependency_id: UUID, tenant_id: UUID) -> Optional[CrossProjectDependencyResponseDTO]:
        entity = self._repo.get_by_id(dependency_id)
        if entity is None:
            return None
        entity.resolve()
        saved = self._repo.save(entity)

        event_bus.publish(DependencyResolved(
            tenant_id=tenant_id,
            dependency_id=saved.id,
        ))

        return self._to_response(saved)

    def reactivate_dependency(self, dependency_id: UUID) -> Optional[CrossProjectDependencyResponseDTO]:
        entity = self._repo.get_by_id(dependency_id)
        if entity is None:
            return None
        entity.reactivate()
        saved = self._repo.save(entity)
        return self._to_response(saved)

    def delete_dependency(self, dependency_id: UUID) -> None:
        self._repo.delete(dependency_id)

    # ── Analysis ──

    def detect_circular_dependencies(self, tenant_id: UUID) -> List[CircularDependencyDTO]:
        """تشخیص وابستگی‌های حلقوی در تمام وابستگی‌های فعال."""
        entities = self._repo.find_active()
        circulars = self._analyzer.detect_circular_dependencies(entities)

        # Publish events for detected circles
        for c in circulars:
            event_bus.publish(CircularDependencyDetected(
                tenant_id=tenant_id,
                cycle=" → ".join(c.cycle),
            ))

        return [
            CircularDependencyDTO(cycle=c.cycle, description=c.description)
            for c in circulars
        ]

    def calculate_critical_chain(self) -> List[CriticalChainLinkDTO]:
        """محاسبه زنجیره بحرانی."""
        entities = self._repo.find_active()
        chain = self._analyzer.calculate_critical_chain(entities)
        return [
            CriticalChainLinkDTO(
                project_id=link.project_id,
                predecessor_id=link.predecessor_id,
                dependency_type=link.dependency_type,
                lag_days=link.lag_days,
                total_slack=link.total_slack,
            )
            for link in chain
        ]

    def impact_analysis(
        self, project_id: str, delay_days: int,
    ) -> ImpactResultDTO:
        """تحلیل اثر تأخیر یک پروژه."""
        entities = self._repo.find_active()
        result = self._analyzer.impact_analysis(entities, project_id, delay_days)
        return ImpactResultDTO(
            delayed_project_id=result.delayed_project_id,
            delay_days=result.delay_days,
            affected_projects=result.affected_projects,
            total_cascade_days=result.total_cascade_days,
        )

    # ── Private ──

    def _to_response(self, entity: CrossProjectDependency) -> CrossProjectDependencyResponseDTO:
        return CrossProjectDependencyResponseDTO(
            id=entity.id,
            predecessor_project_id=entity.predecessor_project_id,
            successor_project_id=entity.successor_project_id,
            predecessor_milestone_id=entity.predecessor_milestone_id,
            successor_milestone_id=entity.successor_milestone_id,
            dependency_type=entity.dependency_type,
            lag_days=entity.lag_days,
            status=entity.status,
            impact_description=entity.impact_description,
            metadata=entity.metadata,
            created_at=entity.created_at,
            updated_at=entity.updated_at,
        )
