"""
MQTT Message Parsers

This module provides parsers for different MQTT message formats from various
power monitoring devices:
- Frient impulse loggers (single power value)
- Shelly Pro 3EM (three-phase power values)

Each parser returns a normalized format: list of (phase, power) tuples
where phase is None for single-phase devices or "A"/"B"/"C" for three-phase.
"""

from __future__ import annotations

import json
import logging
from typing import Optional

log = logging.getLogger(__name__)


class ParseResult:
    """Result of parsing an MQTT message."""
    
    def __init__(
        self,
        power_data: list[tuple[Optional[str], float]],
        energy: Optional[float] = None
    ):
        """
        Args:
            power_data: List of (phase, power_watts) tuples
            energy: Optional cumulative energy in Wh (Frient only)
        """
        self.power_data = power_data
        self.energy = energy
    
    def __repr__(self):
        return f"ParseResult(power_data={self.power_data}, energy={self.energy})"


def parse_mqtt_message(topic: str, payload: bytes) -> Optional[ParseResult]:
    """
    Parse MQTT message from any supported device type.
    
    Auto-detects message format and routes to appropriate parser.
    
    Args:
        topic: MQTT topic
        payload: Raw message payload
        
    Returns:
        ParseResult with normalized power data, or None if unparseable
    """
    try:
        data = json.loads(payload)
    except json.JSONDecodeError:
        log.debug(f"[{topic}] Non-JSON payload, ignoring")
        return None
    
    # Try Frient format first (has 'power' field)
    if "power" in data:
        return parse_frient_message(topic, data)
    
    # Try Shelly format (has 'params' field)
    elif "params" in data:
        return parse_shelly_message(topic, data)
    
    else:
        log.debug(f"[{topic}] No recognized power data in message")
        return None


def parse_frient_message(topic: str, data: dict) -> Optional[ParseResult]:
    """
    Parse Frient impulse logger message.
    
    Format: {'power': 2803, 'energy': 29684380, ...}
    
    Args:
        topic: MQTT topic
        data: Parsed JSON data
        
    Returns:
        ParseResult with single power value (no phase)
    """
    power = data.get("power")
    energy = data.get("energy")
    
    if power is None:
        log.debug(f"[{topic}] Frient message missing 'power' field")
        return None
    
    # Frient returns single power value (no phase)
    power_data = [(None, float(power))]
    
    return ParseResult(
        power_data=power_data,
        energy=float(energy) if energy is not None else None
    )


def parse_shelly_message(topic: str, data: dict) -> Optional[ParseResult]:
    """
    Parse Shelly Pro 3EM message.
    
    Format: {
        'params': {
            'em:0': {
                'a_act_power': 1234.5,
                'b_act_power': 2.3,
                'c_act_power': 4.5,
                ...
            }
        }
    }
    
    Args:
        topic: MQTT topic
        data: Parsed JSON data
        
    Returns:
        ParseResult with three-phase power values
    """
    params = data.get("params", {})
    em = params.get("em:0", {})
    
    # Skip if em:0 is empty or missing (non-power status messages)
    if not em:
        log.debug(f"[{topic}] Shelly message without em:0 data, skipping")
        return None
    
    # Extract three-phase power values
    phases = {
        "A": "a_act_power",
        "B": "b_act_power",
        "C": "c_act_power"
    }
    
    power_data = []
    for phase_label, field_name in phases.items():
        value = em.get(field_name)
        if value is None:
            log.debug(
                f"[{topic}] Missing field {field_name}, "
                f"available fields: {list(em.keys())}"
            )
            return None
        power_data.append((phase_label, float(value)))
    
    return ParseResult(power_data=power_data, energy=None)
