from datetime import datetime, timezone, timedelta
import json
import base64

class Medicion:
    """Modelo de datos para una medición de medidor de agua"""
    
    def __init__(self, message):
        # Datos del mensaje
        self.message = message
        
        # Parsear objectJSON
        self.object_data = json.loads(message['objectJSON'])
        
        # Información del medidor
        self.id_medidor = None  # Se asignará después de buscar en DB
        self.nserie = message.get('deviceName', '')  # Número de serie del dispositivo
        self.status = self.object_data.get('status', 0)  # Status del medidor desde el mensaje
        
        # Obtener fecha del campo publishedAt y convertir a UTC-3
        self.fecha_recepcion = self._parse_published_at(message.get('publishedAt'))
        
        # Datos de la medición
        self.rssi = message.get('rxInfo', [{}])[0].get('rssi', 0)
        
        # Cumulative flow
        self.cumul_flow_unit = self.object_data.get('cumulativeUnit', 0.01)
        self.cumul_flow_value_original = self.object_data.get('cumulativeValue', 0)
        self.cumul_flow_value = round(self.cumul_flow_value_original * self.cumul_flow_unit, 3)
        
        # Daily flow
        self.daily_flow_unit = self.object_data.get('dailyUnit', 0.001)
        self.daily_flow_value_original = self.object_data.get('dailyValue', 0)
        self.daily_flow_value = round(self.daily_flow_value_original * self.daily_flow_unit, 3)
        
        # Reverse flow
        self.reverse_flow_unit = self.object_data.get('reverseUnit', 0.01)
        self.reverse_flow_value_original = self.object_data.get('reverseValue', 0)
        self.reverse_flow_value = round(self.reverse_flow_value_original * self.reverse_flow_unit, 3)
        
        # Flow rate
        self.flow_rate_unit = self.object_data.get('flowRateUnit', 0.0001)
        self.flow_rate_value_original = self.object_data.get('flowRatevalue', 0)  # Nota: typo en el JSON original
        self.flow_rate_value = round(self.flow_rate_value_original * self.flow_rate_unit, 3)
        
        self.temperatura = round(self.object_data.get('temperatura', 0), 1)
        self.meter_time = self._fix_meter_time(self.object_data.get('innerTime', ''))
        
        # Delta acumulado - se calculará en el procesador
        self.delta_acumulado = None
    
    def _parse_published_at(self, published_at_str):
        """Convierte publishedAt de UTC a UTC-3"""
        if not published_at_str:
            # Fallback a fecha actual si no hay publishedAt
            return datetime.now(timezone(timedelta(hours=-3)))
        
        try:
            # Parsear fecha UTC (formato: 2025-06-02T15:43:05.841430287Z)
            # Remover la Z final y parsear
            if published_at_str.endswith('Z'):
                published_at_str = published_at_str[:-1]
            
            # Parsear la fecha como UTC
            utc_date = datetime.fromisoformat(published_at_str).replace(tzinfo=timezone.utc)
            
            # Convertir a UTC-3
            utc_minus_3 = timezone(timedelta(hours=-3))
            local_date = utc_date.astimezone(utc_minus_3)
            
            return local_date
            
        except (ValueError, AttributeError) as e:
            # En caso de error, usar fecha actual UTC-3
            return datetime.now(timezone(timedelta(hours=-3)))
    
    def _fix_meter_time(self, meter_time_str):
        """Corrige el formato de fecha del medidor si es necesario"""
        if not meter_time_str:
            return None
            
        try:
            # Si la fecha tiene formato incorrecto como '020-25-06', corregir a '2025-06'
            if meter_time_str.startswith('020-'):
                meter_time_str = '2' + meter_time_str[1:]
            
            # Parsear la fecha
            from datetime import datetime
            return datetime.strptime(meter_time_str, '%Y-%m-%d %H:%M:%S')
        except Exception as e:
            # Si no se puede parsear, retornar None
            return None
    
    def get_device_identifier(self, message):
        """Obtiene el identificador del dispositivo desde devEUI (base64 to hex)"""
        try:
            dev_eui_b64 = message.get('devEUI', '')
            if not dev_eui_b64:
                return None
                
            # Decodificar base64 a bytes
            dev_eui_bytes = base64.b64decode(dev_eui_b64)
            
            # Convertir bytes a hexadecimal (mayúsculas)
            dev_eui_hex = dev_eui_bytes.hex().upper()
            
            return dev_eui_hex
            
        except Exception as e:
            return None
    
    def to_dict(self):
        """Convierte el objeto a diccionario para inserción en DB"""
        return {
            'idMedidor': self.id_medidor,
            'nserie': self.nserie,
            'fecha_recepcion': self.fecha_recepcion,
            'meter_time': self.meter_time,
            'rssi': self.rssi,
            'cumul_flow_value': self.cumul_flow_value,
            'daily_flow_value': self.daily_flow_value,
            'reverse_flow_value': self.reverse_flow_value,
            'flow_rate_value': self.flow_rate_value,
            'temperatura': self.temperatura,
            'delta_acumulado': self.delta_acumulado,
            'status': self.status
        } 