"""Reply telegram model for console bus communication.

Reply telegrams are responses to system telegrams, containing the requested data
like temperature readings, status information, etc.
"""

from dataclasses import dataclass
from datetime import datetime
from typing import Optional, Any
from .datapoint_type import DataPointType
from .system_function import SystemFunction
from .telegram import Telegram
from .telegram_type import TelegramType


@dataclass
class ReplyTelegram(Telegram):
    """
    Represents a parsed reply telegram from the console bus.

    Format: <R{serial_number}F{function_code}D{datapoint_type}{data_value}{checksum}>
    Examples: <R0020012521F02D18+26,0§CIL>
    """

    serial_number: str = ""
    system_function: Optional[SystemFunction] = None
    data: str = ""
    datapoint_type: Optional[DataPointType] = None
    data_value: str = ""

    def __post_init__(self) -> None:
        if self.timestamp is None:
            self.timestamp = datetime.now()
        self.telegram_type = TelegramType.REPLY

    @property
    def parsed_value(self) -> dict[str, Any]:
        """Parse the data value based on data point type"""
        if self.datapoint_type == DataPointType.TEMPERATURE:
            return self._parse_temperature_value()
        elif self.datapoint_type == DataPointType.SW_TOP_VERSION:
            return self._parse_humidity_value()
        elif self.datapoint_type == DataPointType.VOLTAGE:
            return self._parse_voltage_value()
        elif self.datapoint_type == DataPointType.MODULE_ENERGY_LEVEL:
            return self._parse_current_value()
        elif self.datapoint_type == DataPointType.MODULE_TYPE:
            return self._parse_module_type_value()
        elif self.datapoint_type == DataPointType.SW_VERSION:
            return self._parse_sw_version_value()
        return {"raw_value": self.data_value, "parsed": False}

    def _parse_temperature_value(self) -> dict:
        """Parse temperature value like '+26,0§C'"""
        try:
            # Remove unit indicator (§C)
            value_part = self.data_value.replace("§C", "")
            # Replace comma with dot for decimal
            value_str = value_part.replace(",", ".")
            temperature = float(value_str)

            return {
                "value": temperature,
                "unit": "°C",
                "formatted": f"{temperature:.1f}°C",
                "raw_value": self.data_value,
                "parsed": True,
            }
        except (ValueError, AttributeError):
            return {
                "raw_value": self.data_value,
                "parsed": False,
                "error": "Failed to parse temperature",
            }

    def _parse_humidity_value(self) -> dict:
        """Parse humidity value like '+65,5§H'"""
        try:
            # Remove unit indicator (§H)
            value_part = self.data_value.replace("§RH", "")
            # Replace comma with dot for decimal
            value_str = value_part.replace(",", ".")
            humidity = float(value_str)

            return {
                "value": humidity,
                "unit": "%RH",
                "formatted": f"{humidity:.1f}%RH",
                "raw_value": self.data_value,
                "parsed": True,
            }
        except (ValueError, AttributeError):
            return {
                "raw_value": self.data_value,
                "parsed": False,
                "error": "Failed to parse humidity",
            }

    def _parse_voltage_value(self) -> dict:
        """Parse voltage value like '+12,5§V'"""
        try:
            # Remove unit indicator (§V)
            value_part = self.data_value.replace("§V", "")
            # Replace comma with dot for decimal
            value_str = value_part.replace(",", ".")
            voltage = float(value_str)

            return {
                "value": voltage,
                "unit": "V",
                "formatted": f"{voltage:.1f}V",
                "raw_value": self.data_value,
                "parsed": True,
            }
        except (ValueError, AttributeError):
            return {
                "raw_value": self.data_value,
                "parsed": False,
                "error": "Failed to parse voltage",
            }

    def _parse_current_value(self) -> dict:
        """Parse current value like '+0,25§A'"""
        try:
            # Remove unit indicator (§A)
            value_part = self.data_value.replace("§A", "")
            # Replace comma with dot for decimal
            value_str = value_part.replace(",", ".")
            current = float(value_str)

            return {
                "value": current,
                "unit": "A",
                "formatted": f"{current:.2f}A",
                "raw_value": self.data_value,
                "parsed": True,
            }
        except (ValueError, AttributeError):
            return {
                "raw_value": self.data_value,
                "parsed": False,
                "error": "Failed to parse current",
            }

    def _parse_module_type_value(self) -> dict:
        """Parse status value"""
        # Status values are typically alphanumeric codes
        return {
            "module_type": self.data_value,
            "raw_value": self.data_value,
            "parsed": True,
        }

    def _parse_sw_version_value(self) -> dict:
        """Parse version value like 'XP230_V1.00.04'"""
        try:
            # Version format: {PRODUCT}_{VERSION}
            # Examples: XP230_V1.00.04, XP20_V0.01.05, XP33LR_V0.04.02, XP24_V0.34.03
            if "_V" in self.data_value:
                parts = self.data_value.split("_V", 1)
                if len(parts) == 2:
                    product = parts[0]
                    version = parts[1]

                    return {
                        "product": product,
                        "version": version,
                        "full_version": self.data_value,
                        "formatted": f"{product} v{version}",
                        "raw_value": self.data_value,
                        "parsed": True,
                    }

            # If format doesn't match expected pattern, treat as raw
            return {
                "full_version": self.data_value,
                "formatted": self.data_value,
                "raw_value": self.data_value,
                "parsed": False,
                "error": "Version format not recognized",
            }

        except (ValueError, AttributeError):
            return {
                "raw_value": self.data_value,
                "parsed": False,
                "error": "Failed to parse version",
            }

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization"""
        parsed_data = self.parsed_value

        return {
            "serial_number": self.serial_number,
            "system_function": (
                {
                    "code": (
                        self.system_function.value if self.system_function else None
                    ),
                    "description": (
                        self.system_function.name if self.system_function else None
                    ),
                }
                if self.system_function
                else None
            ),
            "datapoint_type": (
                {
                    "code": self.datapoint_type.value if self.datapoint_type else None,
                    "description": (
                        self.datapoint_type.name if self.datapoint_type else None
                    ),
                }
                if self.datapoint_type
                else None
            ),
            "data_value": {"raw": self.data_value, "parsed": parsed_data},
            "checksum": self.checksum,
            "checksum_validated": self.checksum_validated,
            "raw_telegram": self.raw_telegram,
            "timestamp": self.timestamp.isoformat() if self.timestamp else None,
            "telegram_type": self.telegram_type.value,
        }

    def __str__(self) -> str:
        """Human-readable string representation"""
        parsed = self.parsed_value
        if parsed.get("parsed", False) and "formatted" in parsed:
            value_display = parsed["formatted"]
        else:
            value_display = self.data_value

        system_func_name = (
            self.system_function.name if self.system_function else "Unknown"
        )
        datapoint_name = self.datapoint_type.name if self.datapoint_type else "Unknown"
        return (
            f"Reply Telegram: {system_func_name}\n "
            f"for {datapoint_name} = {value_display} "
            f"from device {self.serial_number}"
        )
