"""Heating Orchestrator.

The orchestrator composes use cases to implement complex workflows.
It coordinates multiple use cases but contains NO business logic itself.

This is the main entry point for heating operations from the infrastructure layer.
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from .use_cases import (
    CalculateAnticipationUseCase,
    CheckOvershootRiskUseCase,
    ControlPreheatingUseCase,
    ScheduleAnticipationActionUseCase,
    UpdateCacheDataUseCase,
)

if TYPE_CHECKING:
    from datetime import datetime
    from typing import Any

_LOGGER = logging.getLogger(__name__)


class HeatingOrchestrator:
    """Orchestrates heating use cases.

    The orchestrator is responsible for:
    1. Composing use cases to implement workflows
    2. Coordinating the execution order of use cases
    3. Managing cross-use-case dependencies

    NO business logic - pure composition and coordination.
    """

    def __init__(
        self,
        calculate_anticipation: CalculateAnticipationUseCase,
        control_preheating: ControlPreheatingUseCase,
        schedule_anticipation_action: ScheduleAnticipationActionUseCase,
        check_overshoot_risk: CheckOvershootRiskUseCase,
        update_cache: UpdateCacheDataUseCase,
    ) -> None:
        """Initialize the orchestrator with use cases.

        Args:
            calculate_anticipation: Use case for calculating anticipation data
            control_preheating: Use case for controlling preheating
            schedule_anticipation_action: Use case for scheduling anticipation actions
            check_overshoot_risk: Use case for checking overshoot risk
            update_cache: Use case for updating cache
        """
        _LOGGER.debug("Initializing HeatingOrchestrator")
        self._calculate_anticipation = calculate_anticipation
        self._control_preheating = control_preheating
        self._schedule_anticipation_action = schedule_anticipation_action
        self._check_overshoot_risk = check_overshoot_risk
        self._update_cache = update_cache

    async def calculate_anticipation_only(
        self,
        target_time: datetime | None = None,
        target_temp: float | None = None,
    ) -> dict:
        """Calculate anticipation data only (no scheduling).

        For users who use the service without a scheduler (via REST API).

        Args:
            target_time: Target time for heating
            target_temp: Target temperature

        Returns:
            Dict with anticipation data
        """
        _LOGGER.debug("Entering HeatingOrchestrator.calculate_anticipation_only()")

        result = await self._calculate_anticipation.calculate_anticipation_datas(
            target_time=target_time,
            target_temp=target_temp,
        )

        _LOGGER.debug("Exiting calculate_anticipation_only() -> data")
        return result

    async def disable_preheating(self, scheduler_entity_id: str) -> None:
        """Disable preheating (cancel timer and active preheating).

        Args:
            scheduler_entity_id: Scheduler entity to cancel
        """
        _LOGGER.debug("Entering HeatingOrchestrator.disable_preheating()")

        # Delegate to schedule_anticipation_action to cancel timer
        await self._schedule_anticipation_action.cancel_action()

        # Cancel active preheating if any
        await self._control_preheating.cancel_preheating(scheduler_entity_id)

        _LOGGER.info("Preheating disabled")
        _LOGGER.debug("Exiting HeatingOrchestrator.disable_preheating()")

    async def reset_all_learning_data(self, device_id: str) -> None:
        """Reset all learned data (LHS + cycles).

        Args:
            device_id: Device identifier
        """
        _LOGGER.debug("Entering HeatingOrchestrator.reset_all_learning_data()")

        await self._update_cache.reset_cache(device_id)

        _LOGGER.debug("Exiting HeatingOrchestrator.reset_all_learning_data()")

    def is_preheating_active(self) -> bool:
        """Check if preheating is currently active.

        Returns:
            True if preheating is active, False otherwise
        """
        return self._control_preheating.is_preheating_active()

    async def calculate_and_schedule_anticipation(self, ihp_enabled: bool = True) -> dict[str, Any]:
        """Calculate anticipation and handle scheduling based on IHP status.

        This orchestrator method:
        1. Calculates anticipation data
        2. Delegates scheduling decisions to ScheduleAnticipationActionUseCase
        3. Always returns anticipation data structure

        Args:
            ihp_enabled: Whether IHP preheating is enabled

        Returns:
            Dict with anticipation data for sensors (always returns structure)
        """
        _LOGGER.debug(
            "Entering HeatingOrchestrator.calculate_and_schedule_anticipation(ihp_enabled=%s)",
            ihp_enabled,
        )

        # Step 1: Always calculate anticipation data regardless of IHP state.
        # The switch only controls whether preheating is scheduled, not whether
        # calculations happen. This ensures sensors and LHS caches stay up-to-date.
        anticipation_data = await self._calculate_anticipation.calculate_anticipation_datas()

        # Step 2: Delegate scheduling decisions to use case (respects ihp_enabled)
        await self._schedule_anticipation_action.handle_anticipation_scheduling(
            anticipation_data,
            ihp_enabled,
        )

        _LOGGER.debug("Exiting HeatingOrchestrator.calculate_and_schedule_anticipation() -> data")
        return anticipation_data

    async def check_and_prevent_overshoot(self, scheduler_entity_id: str) -> bool:
        """Check overshoot risk and cancel preheating if needed.

        Args:
            scheduler_entity_id: Scheduler entity to cancel if overshoot detected

        Returns:
            True if overshoot detected and cancellation triggered, False otherwise
        """
        _LOGGER.debug(
            "Entering HeatingOrchestrator.check_and_prevent_overshoot(scheduler=%s)",
            scheduler_entity_id,
        )

        overshoot_detected = await self._check_overshoot_risk.check_and_prevent_overshoot(
            scheduler_entity_id=scheduler_entity_id
        )

        if overshoot_detected:
            await self._schedule_anticipation_action.cancel_action()

        _LOGGER.debug(
            "Exiting HeatingOrchestrator.check_and_prevent_overshoot() -> %s",
            overshoot_detected,
        )
        return overshoot_detected
