// src/mqtt/handlers/evse.handler.js
async function handleStateEvse(ctx, mqttTopic, payload) {
    const charger = await ctx.getChargerByMqttTopic(mqttTopic);
    if (!charger) {
        console.warn(`[MQTT] Charger não encontrado para topic: ${mqttTopic}`);
        return;
    }

    const chargerId = charger.id;
    const now = new Date();

    const rawStatus = payload?.status || payload?.state || '';
    const stateCode = ctx.inferStateCode(rawStatus);
    if (!stateCode) {
        console.warn(`[MQTT] state/evse sem stateCode válido (charger ${chargerId})`);
        return;
    }

    const status = ctx.getStatusFromStateCode(stateCode);
    ctx.lastMetaByChargerId.set(chargerId, { status, stateCode, rawStatus });

    const isCharging = stateCode === 'C2';

    // do firmware: chargers[0].current / power (W)
    const ch0 = Array.isArray(payload?.chargers) ? payload.chargers[0] : null;

    // ✅ current guardado com 2 casas (e só quando está a carregar)
    const currentA = isCharging ? ctx.round2(ch0?.current) : 0;

    // ✅ power vem em W -> guardar kW com 2 casas (e só quando está a carregar)
    const powerKw = isCharging ? ctx.wToKw2(ch0?.power) : 0;

    const dbUpdate = {
        status,
        charging_current: currentA,

        power_l1: powerKw,
        power_l2: 0,
        power_l3: 0,

        current_l1: currentA,
        current_l2: 0,
        current_l3: 0,

        updated_at: now.toISOString(),
    };

    await ctx.updateChargerDbIfChanged(chargerId, dbUpdate);

    // Sessões start/stop baseado em C2
    const previouslyEnabled = ctx.lastEnabled[chargerId] || false;
    const currentlyEnabled = isCharging;

    if (!previouslyEnabled && currentlyEnabled) {
        const startEnergy = ctx.lastTotalEnergyByChargerId.get(chargerId) ?? 0;
        ctx.sessionStartEnergyByChargerId.set(chargerId, startEnergy);

        const activeSession = await ctx.db('charger_sessions')
            .where({ charger_id: chargerId })
            .whereNull('ended_at')
            .first();

        if (!activeSession) {
            await ctx.db('charger_sessions').insert({
                charger_id: chargerId,
                started_at: now,
                kwh: 0,
            });
            console.log(`[DB] Sessão iniciada para charger ID ${chargerId}`);
        }
    }

    if (previouslyEnabled && !currentlyEnabled) {
        const session = await ctx.db('charger_sessions')
            .where({ charger_id: chargerId })
            .whereNull('ended_at')
            .first();

        if (session) {
            const endEnergy = ctx.lastTotalEnergyByChargerId.get(chargerId) ?? 0;
            const startEnergy = ctx.sessionStartEnergyByChargerId.get(chargerId) ?? 0;
            const delta = Math.max(0, ctx.round2(endEnergy - startEnergy));

            await ctx.db('charger_sessions')
                .where({ id: session.id })
                .update({ ended_at: now, kwh: delta });

            console.log(`[DB] Sessão finalizada para charger ID ${chargerId} (kWh=${delta})`);
        }

        ctx.sessionStartEnergyByChargerId.delete(chargerId);

        await ctx.sendPushToUser(charger.user_id, {
            title: '✅ Carregamento concluído',
            body: `${charger.location || 'Carregador'} terminou o carregamento.`,
            url: `/history`,
        });
    }

    ctx.lastEnabled[chargerId] = currentlyEnabled;

    // ✅ também normalizamos o que vai para o socket (opcional mas consistente)
    const consumption = ctx.round2(ctx.lastTotalEnergyByChargerId.get(chargerId) ?? 0);
    const chargingTime = ctx.round2(ctx.toNum(payload?.chargingTime) || 0);

    ctx.emitter.emit('charging-status', {
        charger_id: chargerId,
        mqtt_topic: mqttTopic,
        status,
        stateCode,
        consumption,
        chargingTime,
        power: [powerKw, 0, 0],
        voltage: [0, 0, 0],
        current: [currentA, 0, 0],
        raw: payload,
    });

    if (status === '⚠️ Fault' || status === '❌ CP Error') {
        await ctx.sendPushToUser(charger.user_id, {
            title: '⚠️ Erro no carregador',
            body: `${charger.location || 'Carregador'} entrou em falha.`,
            url: `/charger/${charger.id}`,
        });
    }
}

async function handleStateScheduler(ctx, mqttTopic, payload) {
    const charger = await ctx.getChargerByMqttTopic(mqttTopic);
    if (!charger) return;

    ctx.emitter.emit('scheduler-state', {
        charger_id: charger.id,
        mqtt_topic: mqttTopic,
        ...payload,
        updated_at: new Date().toISOString(),
    });
}

async function handleStateLoadbalancing(ctx, mqttTopic, payload) {
    const charger = await ctx.getChargerByMqttTopic(mqttTopic);
    if (!charger) return;

    ctx.emitter.emit('loadbalancing-state', {
        charger_id: charger.id,
        mqtt_topic: mqttTopic,
        ...payload,
        updated_at: new Date().toISOString(),
    });
}

async function handleStateAuth(ctx, mqttTopic, payload) {
    const charger = await ctx.getChargerByMqttTopic(mqttTopic);
    if (!charger) return;

    ctx.emitter.emit('auth-state', {
        charger_id: charger.id,
        mqtt_topic: mqttTopic,
        ...payload,
        updated_at: new Date().toISOString(),
    });
}

async function handleStateMetersConfig(ctx, mqttTopic, payload) {
    const charger = await ctx.getChargerByMqttTopic(mqttTopic);
    if (!charger) return;

    ctx.emitter.emit('meters-config', {
        charger_id: charger.id,
        mqtt_topic: mqttTopic,
        ...payload,
        updated_at: new Date().toISOString(),
    });
}

module.exports = {
    handleStateEvse,
    handleStateScheduler,
    handleStateLoadbalancing,
    handleStateAuth,
    handleStateMetersConfig,
};
