"""Base parser for SolaX inverter data arrays."""

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass

from ..models import InverterData


@dataclass(frozen=True)
class RegisterDefinition:
    """Definition of a single register in the Data array.

    Attributes:
        field_name: Name of the InverterData field.
        index: Index into the Data array.
        scale: Divisor for scaling (1 = no scaling, 10 = /10, 100 = /100).
        signed: Whether the value is signed (two's complement for 16-bit).
        high_index: Index of the high word for 32-bit values. If set,
            the value is computed as data[index] + data[high_index] * 65536.
    """

    field_name: str
    index: int
    scale: int = 1
    signed: bool = False
    high_index: int | None = None


class InverterParser(ABC):
    """Abstract base class for inverter data parsers."""

    @property
    @abstractmethod
    def inverter_type(self) -> int:
        """Return the inverter type code this parser handles."""

    @property
    @abstractmethod
    def model_name(self) -> str:
        """Return a human-readable model name."""

    @property
    @abstractmethod
    def registers(self) -> tuple[RegisterDefinition, ...]:
        """Return the register definitions for this model."""

    def parse(self, data: list[int]) -> InverterData:
        """Parse a Data array into an InverterData instance."""
        values: dict[str, float | int] = {}

        for reg in self.registers:
            raw = data[reg.index]

            if reg.high_index is not None:
                raw = raw + data[reg.high_index] * 65536
            elif reg.signed and raw > 32767:
                raw -= 65536

            if reg.scale == 1:
                values[reg.field_name] = raw
            else:
                values[reg.field_name] = raw / reg.scale

        return InverterData(**values)
