"""Climate platform for Climate Scheduler."""
import asyncio
import logging
from typing import Any, Dict, List, Optional
from datetime import datetime, timedelta, time

from homeassistant.components.climate import (
    ClimateEntity,
    ClimateEntityFeature,
    HVACMode,
    HVACAction,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.unit_conversion import TemperatureConverter

from .const import DOMAIN
from .coordinator import HeatingSchedulerCoordinator
from .storage import ScheduleStorage

_LOGGER = logging.getLogger(__name__)

__all__ = ["async_setup_entry", "ClimateSchedulerGroupEntity"]


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up Climate Scheduler climate entities from a config entry."""
    storage: ScheduleStorage = hass.data[DOMAIN]["storage"]
    coordinator: HeatingSchedulerCoordinator = hass.data[DOMAIN]["coordinator"]
    
    # Get all groups - create climate cards for all groups with entities
    groups = await storage.async_get_groups()
    entities = []
    groups_normalized = False
    
    for group_name, group_data in groups.items():
        # Normalize _is_single_entity_group flag based on actual entity count
        # This fixes inconsistency where groups with 1 entity might not have the flag set
        entity_count = len(group_data.get("entities", []))
        is_single_entity = entity_count == 1
        has_flag = group_data.get("_is_single_entity_group", False)
        
        # If flag doesn't match actual entity count, normalize it
        if is_single_entity != has_flag:
            group_data["_is_single_entity_group"] = is_single_entity
            groups_normalized = True
            _LOGGER.info(
                f"Normalized _is_single_entity_group flag for group '{group_name}': "
                f"entity_count={entity_count}, flag={is_single_entity}"
            )
        
        # Skip virtual groups (no entities) - but include all groups with at least one entity
        if entity_count == 0:
            continue
        
        # Create climate entity for this group (including single-entity groups)
        entities.append(
            ClimateSchedulerGroupEntity(
                coordinator,
                storage,
                group_name,
                group_data,
            )
        )
        _LOGGER.info(f"Created climate entity for group '{group_name}' with {entity_count} entities")
    
    # Save normalized flags if any were updated
    if groups_normalized:
        await storage.async_save()
        _LOGGER.info("Saved normalized group flags to storage")
    
    if entities:
        async_add_entities(entities, True)
        _LOGGER.info(f"Added {len(entities)} climate scheduler group entities")


class ClimateSchedulerGroupEntity(CoordinatorEntity, ClimateEntity):
    """Climate entity representing a schedule group."""

    _attr_has_entity_name = True

    def __init__(
        self,
        coordinator: HeatingSchedulerCoordinator,
        storage: ScheduleStorage,
        group_name: str,
        group_data: Dict[str, Any],
    ) -> None:
        """Initialize the climate entity."""
        super().__init__(coordinator)
        
        self._storage = storage
        self._group_name = group_name
        self._attr_has_entity_name = True
        self._attr_name = f"Climate Schedule {group_name}"
        self._attr_unique_id = f"climate_scheduler_group_{group_name.lower().replace(' ', '_')}"
        
        # Climate entity configuration - will be set when added to hass
        self._attr_temperature_unit = UnitOfTemperature.CELSIUS  # Default, updated in async_added_to_hass
        self._attr_supported_features = (
            ClimateEntityFeature.TARGET_TEMPERATURE |
            ClimateEntityFeature.TURN_ON |
            ClimateEntityFeature.TURN_OFF |
            ClimateEntityFeature.PRESET_MODE
        )
        
        # Temperature control settings
        self._attr_min_temp = 5.0
        self._attr_max_temp = 35.0
        self._attr_target_temp_step = 0.5
        
        # Simplified modes: Auto (Active - follows schedule) or Off (Idle)
        self._attr_hvac_modes = [
            HVACMode.AUTO,  # Active - follows schedule
            HVACMode.OFF,   # Idle - turns off members
        ]
        
        # Preset modes from profiles
        profiles = group_data.get("profiles", {})
        self._attr_preset_modes = list(profiles.keys()) if profiles else []
        self._attr_preset_mode = group_data.get("active_profile", "Default")
        
        # State tracking
        self._member_entities: List[str] = group_data.get("entities", [])
        self._enabled: bool = group_data.get("enabled", True)
        self._attr_current_temperature: Optional[float] = None
        self._attr_target_temperature: Optional[float] = None
        self._attr_hvac_mode: Optional[HVACMode] = HVACMode.AUTO if self._enabled else HVACMode.OFF
        self._attr_hvac_action: Optional[HVACAction] = None  # Will be set in _update_state
        
        # Cache for attributes
        self._active_node: Optional[Dict[str, Any]] = None
        self._next_node: Optional[Dict[str, Any]] = None
        self._member_temps: Dict[str, float] = {}
    
    async def async_added_to_hass(self) -> None:
        """When entity is added to hass, set temperature unit from system config."""
        await super().async_added_to_hass()
        # Use the same approach as storage.py - get temperature unit from system config
        self._attr_temperature_unit = self.hass.config.units.temperature_unit
        
        # Set temperature step from first member entity if available
        if self._member_entities:
            first_member = self.hass.states.get(self._member_entities[0])
            if first_member:
                member_step = first_member.attributes.get("target_temp_step", 0.5)
                self._attr_target_temp_step = member_step
        
        _LOGGER.debug(
            "Climate entity %s initialized with temperature unit: %s, step: %s",
            self.entity_id,
            self._attr_temperature_unit,
            self._attr_target_temp_step,
        )
        # Perform initial state update
        self._update_state()
        
    @property
    def unique_id(self) -> str:
        """Return unique ID."""
        return self._attr_unique_id
    
    @property
    def device_info(self):
        """Return device info to link this entity to the Climate Scheduler integration."""
        return {
            "identifiers": {(DOMAIN, "climate_scheduler")},
            "name": "Climate Scheduler",
            "manufacturer": "Climate Scheduler",
            "model": "Schedule Manager",
        }
    
    @callback
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        # Update enabled state and profiles from storage
        group_data = self._storage._data.get("groups", {}).get(self._group_name)
        if group_data:
            self._enabled = group_data.get("enabled", True)
            profiles = group_data.get("profiles", {})
            self._attr_preset_modes = list(profiles.keys()) if profiles else []
            self._attr_preset_mode = group_data.get("active_profile", "Default")
            # Update HVAC mode based on enabled state
            self._attr_hvac_mode = HVACMode.AUTO if self._enabled else HVACMode.OFF
        self._update_state()
        self.async_write_ha_state()
    
    def _update_state(self) -> None:
        """Update entity state from member entities and schedule."""
        # 1. Calculate average current temperature from members (in their native unit)
        temps = []
        temp_map = {}
        
        for entity_id in self._member_entities:
            state = self.hass.states.get(entity_id)
            if state and state.attributes.get("current_temperature") is not None:
                try:
                    temp = float(state.attributes["current_temperature"])
                    # Store temperature in its native unit, no conversion
                    temps.append(temp)
                    temp_map[entity_id] = round(temp, 1)
                except (ValueError, TypeError):
                    pass
        
        if temps:
            self._attr_current_temperature = round(sum(temps) / len(temps), 1)
        else:
            self._attr_current_temperature = None
        
        self._member_temps = temp_map
        
        # 2. Check if any member is actively requesting heat/cool and determine overall action
        heating_count = 0
        cooling_count = 0
        for entity_id in self._member_entities:
            state = self.hass.states.get(entity_id)
            if state:
                hvac_action = state.attributes.get("hvac_action")
                if hvac_action == "heating":
                    heating_count += 1
                elif hvac_action == "cooling":
                    cooling_count += 1
        
        # Set hvac_action based on member states and enabled status
        if not self._enabled:
            self._attr_hvac_action = HVACAction.OFF
        elif heating_count > 0:
            self._attr_hvac_action = HVACAction.HEATING
        elif cooling_count > 0:
            self._attr_hvac_action = HVACAction.COOLING
        else:
            self._attr_hvac_action = HVACAction.IDLE
        
        # 3. Get active node from schedule to determine setpoint
        current_time = datetime.now().time()
        current_day = datetime.now().strftime('%a').lower()
        
        # Get the schedule data from storage (synchronously accessible)
        group_data = self._storage._data.get("groups", {}).get(self._group_name, {})
        schedule_mode = group_data.get("schedule_mode", "all_days")
        schedules = group_data.get("schedules", {})
        
        # Get nodes for current day using the same logic as coordinator
        if schedule_mode == "all_days":
            nodes = schedules.get("all_days", [])
        elif schedule_mode == "5/2":
            if current_day in ["mon", "tue", "wed", "thu", "fri"]:
                nodes = schedules.get("weekday", [])
            else:
                nodes = schedules.get("weekend", [])
        else:  # individual
            nodes = schedules.get(current_day, [])
        
        # In individual or 5/2 mode, if current time is before all nodes today,
        # use previous day's last node
        if schedule_mode in ["individual", "5/2"] and nodes:
            sorted_nodes = sorted(nodes, key=lambda n: self._storage._time_to_minutes(n["time"]))
            current_minutes = current_time.hour * 60 + current_time.minute
            if sorted_nodes and current_minutes < self._storage._time_to_minutes(sorted_nodes[0]["time"]):
                # We're before the first node of today, need previous day/period's last node
                days_of_week = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
                current_day_index = days_of_week.index(current_day)
                prev_day = days_of_week[(current_day_index - 1) % 7]
                
                # Get previous day's nodes based on schedule mode
                if schedule_mode == "5/2":
                    # In 5/2 mode, determine if previous day is weekday or weekend
                    if prev_day in ["mon", "tue", "wed", "thu", "fri"]:
                        prev_day_nodes = schedules.get("weekday", [])
                    else:
                        prev_day_nodes = schedules.get("weekend", [])
                else:
                    # In individual mode, use specific day
                    prev_day_nodes = schedules.get(prev_day, [])
                
                if prev_day_nodes:
                    sorted_prev_nodes = sorted(prev_day_nodes, key=lambda n: self._storage._time_to_minutes(n["time"]))
                    last_prev_node = sorted_prev_nodes[-1]
                    # Prepend previous day's last node with time "00:00"
                    carryover_node = {**last_prev_node, "time": "00:00"}
                    nodes = [carryover_node] + nodes
        
        # Determine the active setpoint from schedule
        active_setpoint = None
        if nodes:
            active_node = self._storage.get_active_node(nodes, current_time)
            if active_node:
                active_setpoint = active_node.get("temp")
                _LOGGER.debug(f"Active node for {self._group_name}: temp={active_setpoint}")
            else:
                _LOGGER.debug(f"No active node for {self._group_name} at {current_time}")
        else:
            _LOGGER.debug(f"No schedule data for {self._group_name} on {current_day}")
        
        # Show the scheduled setpoint as target temperature, or use a default
        if active_setpoint is not None:
            self._attr_target_temperature = active_setpoint
        else:
            # Fallback: use average of member target temps, or 20°C default
            member_targets = []
            for entity_id in self._member_entities:
                state = self.hass.states.get(entity_id)
                if state and state.attributes.get("temperature") is not None:
                    try:
                        member_targets.append(float(state.attributes["temperature"]))
                    except (ValueError, TypeError):
                        pass
            
            if member_targets:
                self._attr_target_temperature = round(sum(member_targets) / len(member_targets), 1)
            else:
                self._attr_target_temperature = 20.0  # Default fallback
            
            _LOGGER.debug(f"No schedule setpoint for {self._group_name}, using fallback: {self._attr_target_temperature}")
        
        # HVAC mode reflects enabled state (not member states)
        # This is already set in _handle_coordinator_update
        
        self._active_node = None
        self._next_node = None
    
    def _map_hvac_mode(self, mode_str: str) -> HVACMode:
        """Map string hvac_mode to HVACMode enum."""
        mapping = {
            "off": HVACMode.OFF,
            "heat": HVACMode.HEAT,
            "cool": HVACMode.COOL,
            "heat_cool": HVACMode.HEAT_COOL,
            "auto": HVACMode.AUTO,
            "dry": HVACMode.DRY,
            "fan_only": HVACMode.FAN_ONLY,
        }
        return mapping.get(mode_str.lower() if mode_str else "heat", HVACMode.HEAT)
    
    @property
    def extra_state_attributes(self) -> Dict[str, Any]:
        """Return entity specific state attributes."""
        attrs = {
            "member_entities": self._member_entities,
            "member_count": len(self._member_entities),
            "group_name": self._group_name,
            "schedule_enabled": self._enabled,
        }
        
        # Add member temperatures if available
        if self._member_temps:
            attrs["member_temperatures"] = self._member_temps
        
        # Placeholder for future phases - active node info
        if self._active_node:
            attrs["active_node"] = {
                "time": self._active_node.get("time"),
                "temp": self._active_node.get("temp"),
                "hvac_mode": self._active_node.get("hvac_mode"),
            }
        
        if self._next_node:
            attrs["next_node"] = {
                "time": self._next_node.get("time"),
                "temp": self._next_node.get("temp"),
                "hvac_mode": self._next_node.get("hvac_mode"),
            }
        
        return attrs
    
    async def async_set_temperature(self, **kwargs) -> None:
        """Set new target temperature for all member entities."""
        temperature = kwargs.get("temperature")
        if temperature is None:
            _LOGGER.warning("No temperature provided to async_set_temperature")
            return
        
        # Apply temperature to all member entities
        for entity_id in self._member_entities:
            try:
                await self.hass.services.async_call(
                    "climate",
                    "set_temperature",
                    {
                        "entity_id": entity_id,
                        "temperature": temperature,
                    },
                    blocking=True,
                )
                _LOGGER.info(f"Set temperature {temperature} for {entity_id}")
            except Exception as e:
                _LOGGER.error(f"Failed to set temperature for {entity_id}: {e}")
        
        # Set override for each member until next scheduled node
        current_time = datetime.now().time()
        current_day = datetime.now().strftime('%a').lower()
        
        group_data = self._storage._data.get("groups", {}).get(self._group_name, {})
        schedules = group_data.get("schedules", {})
        schedule_data = schedules.get(current_day)
        
        if schedule_data and "nodes" in schedule_data:
            nodes = schedule_data["nodes"]
            next_node = self._storage.get_next_node(nodes, current_time)
            if next_node:
                # Calculate when override expires (at next node time)
                next_node_time_str = next_node["time"]
                next_node_hours, next_node_minutes = map(int, next_node_time_str.split(":"))
                override_until = datetime.now().replace(
                    hour=next_node_hours, 
                    minute=next_node_minutes, 
                    second=0, 
                    microsecond=0
                )
                # If next node time is earlier in the day than current time, it's tomorrow
                if override_until <= datetime.now():
                    override_until += timedelta(days=1)
                
                # Set override for all members
                for entity_id in self._member_entities:
                    self.coordinator.override_until[entity_id] = override_until
                
                _LOGGER.info(
                    f"Set manual override for group {self._group_name} until {override_until}"
                )
        
        # Update target temperature immediately and trigger state refresh
        self._attr_target_temperature = temperature
        
        # Schedule a state update after a short delay to allow member entities to react
        async def delayed_update():
            await asyncio.sleep(2)  # Wait for members to start heating
            self._update_state()
            self.async_write_ha_state()
        
        self.hass.async_create_task(delayed_update())
        self.async_write_ha_state()
    
    async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
        """Set HVAC mode - AUTO (active) or OFF (idle)."""
        if hvac_mode == HVACMode.OFF:
            # Turn off schedule (idle mode)
            await self.async_turn_off()
        elif hvac_mode == HVACMode.AUTO:
            # Turn on schedule (active mode)
            await self.async_turn_on()
        else:
            _LOGGER.warning(f"Unsupported HVAC mode {hvac_mode} for climate scheduler group")
    
    async def async_set_preset_mode(self, preset_mode: str) -> None:
        """Set the preset mode (profile) for this group."""
        try:
            await self._storage.async_set_active_profile(self._group_name, preset_mode)
        except ValueError as err:
            _LOGGER.error(f"Profile switch failed for group {self._group_name}: {err}")
            return
        
        # Force coordinator refresh to apply new schedule immediately
        await self.coordinator.async_request_refresh()
        
        _LOGGER.info(f"Set profile {preset_mode} for group {self._group_name}")
    
    async def async_turn_on(self) -> None:
        """Enable the schedule."""
        # Enable schedule for all member entities
        for entity_id in self._member_entities:
            await self._storage.async_set_enabled(entity_id, True)
        self._enabled = True
        self.async_write_ha_state()
        _LOGGER.info("Enabled schedule for group %s", self._group_name)
    
    async def async_turn_off(self) -> None:
        """Disable the schedule."""
        # Disable schedule for all member entities
        for entity_id in self._member_entities:
            await self._storage.async_set_enabled(entity_id, False)
        self._enabled = False
        self.async_write_ha_state()
        _LOGGER.info("Disabled schedule for group %s", self._group_name)
