"""
Strategy Domain — OKR Calculator Service

سرویس محاسبه پیشرفت اهداف بر اساس نتایج کلیدی.
"""

from dataclasses import dataclass
from decimal import Decimal
from typing import List, Optional

from ..entities.objective import Objective
from ..entities.key_result import KeyResult


@dataclass
class ObjectiveProgress:
    """نتیجه محاسبه پیشرفت هدف."""
    objective_id: object
    weighted_progress: Decimal
    key_results_count: int
    completed_count: int
    at_risk_count: int


@dataclass
class CascadeProgress:
    """نتیجه محاسبه پیشرفت آبشاری."""
    objective_id: object
    own_progress: Decimal
    children_progress: Decimal
    combined_progress: Decimal
    children_count: int


class OKRCalculator:
    """
    سرویس دامنه — محاسبه‌گر OKR.

    - محاسبه پیشرفت هدف بر اساس نتایج کلیدی (weighted average)
    - محاسبه آبشاری (cascade) بر اساس اهداف فرزند
    - ارزیابی اطمینان (confidence)
    """

    @staticmethod
    def calculate_objective_progress(
        objective: Objective,
        key_results: List[KeyResult],
    ) -> ObjectiveProgress:
        """
        محاسبه پیشرفت هدف بر اساس نتایج کلیدی.

        فرمول: Weighted Average of Key Results progress
        """
        if not key_results:
            return ObjectiveProgress(
                objective_id=objective.id,
                weighted_progress=Decimal("0"),
                key_results_count=0,
                completed_count=0,
                at_risk_count=0,
            )

        total_weight = sum(kr.weight for kr in key_results)
        if total_weight == 0:
            total_weight = Decimal("1")

        weighted_sum = sum(kr.progress * kr.weight for kr in key_results)
        weighted_progress = (weighted_sum / total_weight).quantize(Decimal("0.01"))

        from ..value_objects.common import ObjectiveStatus
        completed = sum(1 for kr in key_results if kr.status == ObjectiveStatus.ACHIEVED)
        at_risk = sum(1 for kr in key_results if kr.status == ObjectiveStatus.AT_RISK)

        return ObjectiveProgress(
            objective_id=objective.id,
            weighted_progress=weighted_progress,
            key_results_count=len(key_results),
            completed_count=completed,
            at_risk_count=at_risk,
        )

    @staticmethod
    def calculate_cascade_progress(
        objective: Objective,
        own_key_results: List[KeyResult],
        children: List["Objective"],
        children_key_results: dict,  # {objective_id: [KeyResult, ...]}
        own_weight: Decimal = Decimal("0.5"),
    ) -> CascadeProgress:
        """
        محاسبه پیشرفت آبشاری هدف.

        ترکیب پیشرفت خود هدف + میانگین وزنی اهداف فرزند.
        own_weight: وزن پیشرفت خود هدف (0-1). باقی مانده = وزن فرزندان.
        """
        # Own progress
        if own_key_results:
            own_total_weight = sum(kr.weight for kr in own_key_results) or Decimal("1")
            own_weighted = sum(kr.progress * kr.weight for kr in own_key_results)
            own_progress = (own_weighted / own_total_weight).quantize(Decimal("0.01"))
        else:
            own_progress = Decimal("0")

        # Children progress
        if children:
            child_progresses = []
            for child in children:
                child_krs = children_key_results.get(child.id, [])
                if child_krs:
                    c_total_w = sum(kr.weight for kr in child_krs) or Decimal("1")
                    c_weighted = sum(kr.progress * kr.weight for kr in child_krs)
                    child_progresses.append(
                        (c_weighted / c_total_w).quantize(Decimal("0.01")) * child.weight
                    )
                else:
                    child_progresses.append(child.progress * child.weight)

            total_child_weight = sum(c.weight for c in children) or Decimal("1")
            children_progress = (sum(child_progresses) / total_child_weight).quantize(Decimal("0.01"))
        else:
            children_progress = Decimal("0")
            own_weight = Decimal("1")  # No children → 100% own weight

        children_weight = Decimal("1") - own_weight
        combined = (own_progress * own_weight + children_progress * children_weight).quantize(Decimal("0.01"))

        return CascadeProgress(
            objective_id=objective.id,
            own_progress=own_progress,
            children_progress=children_progress,
            combined_progress=combined,
            children_count=len(children),
        )

    @staticmethod
    def assess_confidence(key_results: List[KeyResult]) -> str:
        """
        ارزیابی سطح اطمینان بر اساس پیشرفت نتایج کلیدی.
        """
        from ..value_objects.common import ConfidenceLevel

        if not key_results:
            return ConfidenceLevel.LOW

        avg_progress = sum(kr.progress for kr in key_results) / len(key_results)

        if avg_progress >= Decimal("70"):
            return ConfidenceLevel.HIGH
        elif avg_progress >= Decimal("40"):
            return ConfidenceLevel.MEDIUM
        else:
            return ConfidenceLevel.LOW
