"""
Strategy Application Service — Corporate Policy Management.
"""

from datetime import datetime
from typing import List, Optional
from uuid import UUID

from ..dtos.strategy_dtos import (
    PolicyCreateDTO, PolicyUpdateDTO, PolicyResponseDTO,
    PolicyAckCreateDTO, PolicyAckResponseDTO,
)
from ...domain.entities.policy import Policy
from ...domain.entities.policy_acknowledgment import PolicyAcknowledgment
from ...infrastructure.repositories import (
    DjangoPolicyRepository,
    DjangoPolicyAcknowledgmentRepository,
)
from apps.core.event_bus.events import event_bus
from ...domain.events.strategy_events import (
    PolicyActivated, PolicyRetired, PolicyAcknowledged,
)


class PolicyService:
    """سرویس لایه اپلیکیشن — مدیریت سیاست‌های سازمانی."""

    def __init__(self):
        self.policy_repo = DjangoPolicyRepository()
        self.ack_repo = DjangoPolicyAcknowledgmentRepository()

    # ─── Policy CRUD ──────────────────────────────

    def create_policy(self, dto: PolicyCreateDTO) -> PolicyResponseDTO:
        entity = Policy(
            title=dto.title,
            code=dto.code,
            category=dto.category,
            content=dto.content,
            effective_date=dto.effective_date,
            review_date=dto.review_date,
            owner_id=dto.owner_id,
            approver_id=dto.approver_id,
            document_id=dto.document_id,
            tenant_id=dto.tenant_id,
            metadata=dto.metadata or {},
        )
        saved = self.policy_repo.save(entity)
        return self._to_response(saved)

    def get_policy(self, policy_id: UUID) -> Optional[PolicyResponseDTO]:
        entity = self.policy_repo.find_by_id(policy_id)
        if not entity:
            return None
        return self._to_response(entity)

    def list_policies(self, tenant_id: UUID) -> List[PolicyResponseDTO]:
        entities = self.policy_repo.find_all(tenant_id)
        return [self._to_response(e) for e in entities]

    def update_policy(self, policy_id: UUID, dto: PolicyUpdateDTO) -> Optional[PolicyResponseDTO]:
        entity = self.policy_repo.find_by_id(policy_id)
        if not entity:
            return None
        if dto.title is not None:
            entity.title = dto.title
        if dto.code is not None:
            entity.code = dto.code
        if dto.category is not None:
            entity.category = dto.category
        if dto.content is not None:
            entity.content = dto.content
        if dto.effective_date is not None:
            entity.effective_date = dto.effective_date
        if dto.review_date is not None:
            entity.review_date = dto.review_date
        if dto.owner_id is not None:
            entity.owner_id = dto.owner_id
        if dto.approver_id is not None:
            entity.approver_id = dto.approver_id
        if dto.document_id is not None:
            entity.document_id = dto.document_id
        if dto.metadata is not None:
            entity.metadata = dto.metadata
        saved = self.policy_repo.save(entity)
        return self._to_response(saved)

    def delete_policy(self, policy_id: UUID) -> bool:
        return self.policy_repo.delete(policy_id)

    # ─── Status Workflow ──────────────────────────

    def activate_policy(self, policy_id: UUID) -> Optional[PolicyResponseDTO]:
        entity = self.policy_repo.find_by_id(policy_id)
        if not entity:
            return None
        entity.activate()
        saved = self.policy_repo.save(entity)
        event_bus.publish(PolicyActivated(
            tenant_id=saved.tenant_id,
            data={"policy_id": str(saved.id), "title": saved.title},
        ))
        return self._to_response(saved)

    def submit_for_review(self, policy_id: UUID) -> Optional[PolicyResponseDTO]:
        entity = self.policy_repo.find_by_id(policy_id)
        if not entity:
            return None
        entity.submit_for_review()
        saved = self.policy_repo.save(entity)
        return self._to_response(saved)

    def retire_policy(self, policy_id: UUID) -> Optional[PolicyResponseDTO]:
        entity = self.policy_repo.find_by_id(policy_id)
        if not entity:
            return None
        entity.retire()
        saved = self.policy_repo.save(entity)
        event_bus.publish(PolicyRetired(
            tenant_id=saved.tenant_id,
            data={"policy_id": str(saved.id), "title": saved.title},
        ))
        return self._to_response(saved)

    # ─── Policy Acknowledgment ────────────────────

    def acknowledge_policy(self, dto: PolicyAckCreateDTO) -> PolicyAckResponseDTO:
        entity = PolicyAcknowledgment(
            policy_id=dto.policy_id,
            user_id=dto.user_id,
            acknowledged_at=dto.acknowledged_at or datetime.now(),
            tenant_id=dto.tenant_id,
            metadata=dto.metadata or {},
        )
        saved = self.ack_repo.save(entity)
        event_bus.publish(PolicyAcknowledged(
            tenant_id=saved.tenant_id,
            data={
                "policy_id": str(saved.policy_id),
                "user_id": str(saved.user_id),
            },
        ))
        return self._to_ack_response(saved)

    def list_acknowledgments_by_policy(self, policy_id: UUID) -> List[PolicyAckResponseDTO]:
        entities = self.ack_repo.find_by_policy(policy_id)
        return [self._to_ack_response(e) for e in entities]

    def list_acknowledgments_by_user(self, user_id: UUID) -> List[PolicyAckResponseDTO]:
        entities = self.ack_repo.find_by_user(user_id)
        return [self._to_ack_response(e) for e in entities]

    # ─── Mapping helpers ──────────────────────────

    @staticmethod
    def _to_response(entity: Policy) -> PolicyResponseDTO:
        return PolicyResponseDTO(
            id=entity.id,
            tenant_id=entity.tenant_id,
            title=entity.title,
            code=entity.code,
            category=entity.category,
            content=entity.content,
            version=entity.version,
            status=entity.status,
            effective_date=entity.effective_date,
            review_date=entity.review_date,
            owner_id=entity.owner_id,
            approver_id=entity.approver_id,
            document_id=entity.document_id,
            metadata=entity.metadata,
            created_at=entity.created_at,
            updated_at=entity.updated_at,
        )

    @staticmethod
    def _to_ack_response(entity: PolicyAcknowledgment) -> PolicyAckResponseDTO:
        return PolicyAckResponseDTO(
            id=entity.id,
            tenant_id=entity.tenant_id,
            policy_id=entity.policy_id,
            user_id=entity.user_id,
            acknowledged_at=entity.acknowledged_at,
            metadata=entity.metadata,
            created_at=entity.created_at,
            updated_at=entity.updated_at,
        )
