# app/src/trading/market_intelligence/common/checks.py

from __future__ import annotations

from dataclasses import dataclass, field

from src.trading.market_intelligence.common.enums import (
    CheckStatus,
    ProcessingStage,
)
from src.trading.market_intelligence.common.reasons import ReasonCode
from src.trading.market_intelligence.common.types import (
    ContextDict,
    ReasonText,
)


@dataclass(frozen=True, slots=True)
class EngineCheck:
    # Результат одной архитектурной проверки.
    #
    # Проверка относится не ко всему Engine, а к одному этапу обработки.
    # Например:
    #
    # INPUT
    # CALCULATION
    # VALIDATION
    # RESULT
    #
    # Engine может выполнить несколько независимых проверок,
    # после чего они объединяются в общий отчёт.
    stage: ProcessingStage
    status: CheckStatus
    reason: ReasonCode
    message: ReasonText
    details: ContextDict = field(default_factory=dict)

    @property
    def is_ok(self) -> bool:
        return self.status == CheckStatus.OK

    @property
    def is_warning(self) -> bool:
        return self.status == CheckStatus.WARNING

    @property
    def is_error(self) -> bool:
        return self.status == CheckStatus.ERROR

    @property
    def is_skipped(self) -> bool:
        return self.status == CheckStatus.SKIPPED


@dataclass(frozen=True, slots=True)
class EngineCheckReport:
    # Общий результат внутренних проверок Engine.
    #
    # Отчёт не содержит торговой логики.
    # Его задача — показать, какие этапы обработки были
    # успешно выполнены, а какие завершились предупреждением,
    # ошибкой или были пропущены.
    checks: tuple[EngineCheck, ...] = ()

    @property
    def has_errors(self) -> bool:
        return any(check.is_error for check in self.checks)

    @property
    def has_warnings(self) -> bool:
        return any(check.is_warning for check in self.checks)

    @property
    def has_skipped(self) -> bool:
        return any(check.is_skipped for check in self.checks)

    @property
    def overall_status(self) -> CheckStatus:
        # Общий статус определяется по наиболее серьёзному результату.
        if self.has_errors:
            return CheckStatus.ERROR

        if self.has_warnings:
            return CheckStatus.WARNING

        if self.has_skipped:
            return CheckStatus.SKIPPED

        return CheckStatus.OK

    @property
    def completed_checks(self) -> int:
        return sum(
            check.status != CheckStatus.SKIPPED
            for check in self.checks
        )

    @property
    def total_checks(self) -> int:
        return len(self.checks)


def build_check(
    *,
    stage: ProcessingStage,
    status: CheckStatus,
    reason: ReasonCode,
    message: ReasonText,
    details: ContextDict | None = None,
) -> EngineCheck:
    # Создаёт одну архитектурную проверку.
    #
    # Используется всеми Engine для формирования единого
    # формата внутренних проверок.
    return EngineCheck(
        stage=stage,
        status=status,
        reason=reason,
        message=message,
        details=details or {},
    )


def build_check_report(
    *checks: EngineCheck,
) -> EngineCheckReport:
    # Собирает общий отчёт из набора отдельных проверок.
    #
    # Порядок проверок сохраняется.
    return EngineCheckReport(checks=checks)