// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync

#include "evadapter.h"
#include "../energyarbitrator.h"
#include "../../evcharger.h"
#include "../../types/chargingaction.h"

#include "plugininfo.h"

EvAdapter::EvAdapter(EvCharger *evCharger, EnergyArbitrator *parent)
    : QObject(parent)
    , m_charger(evCharger)
    , m_parent(parent)
{
}

LoadDescriptor EvAdapter::descriptor() const
{
    LoadDescriptor d;
    d.id      = m_charger->thing()->id().toString();
    d.label   = m_charger->name();
    d.adapter = QStringLiteral("evcharger");
    d.priority = 100;

    d.declared.minA   = m_charger->maxChargingCurrentMinValue();
    d.declared.maxA   = m_charger->maxChargingCurrentMaxValue();
    d.declared.phases = static_cast<int>(m_charger->phaseCount());

    d.limits.chargingEnabledLockS = static_cast<int>(m_charger->chargingEnabledLockDuration());
    d.limits.currentChangeLockS   = static_cast<int>(m_charger->chargingCurrentLockDuration());

    d.supportedKinds = { LoadAction::Setpoint };
    return d;
}

LoadTelemetry EvAdapter::telemetry() const
{
    LoadTelemetry t;
    t.currentPowerW = m_charger->currentPower();
    t.available     = m_charger->available();
    t.lastActionAt  = m_lastActionAt;
    return t;
}

LoadContext EvAdapter::toLoadContext(const QDateTime &now) const
{
    Q_UNUSED(now)  // L'EV n'a pas de verrou de palier (pas de waterfall ECS) — now inutilisé ici.
    LoadContext ctx;
    ctx.id      = m_charger->thing()->id().toString();
    ctx.adapter = QStringLiteral("evcharger");
    ctx.label   = m_charger->name();
    ctx.declared = descriptor().declared;
    ctx.limits   = descriptor().limits;

    ctx.telemetry.currentPowerW = m_charger->currentPower();
    ctx.telemetry.pluggedIn     = m_charger->pluggedIn();
    ctx.telemetry.charging      = m_charger->charging();
    return ctx;
}

LoadAction EvAdapter::applyAction(const LoadAction &action, const QDateTime &now)
{
    if (action.kind != LoadAction::Setpoint)
        return action;

    if (action.reason.isEmpty()) {
        qCWarning(dcNymeaEnergy()) << "[EvAdapter]" << m_charger->name()
                                   << "— LoadAction sans reason rejetée.";
        return action;
    }

    const uint minA = m_charger->maxChargingCurrentMinValue();
    const uint maxA = m_charger->maxChargingCurrentMaxValue();
    const uint clampedA = static_cast<uint>(
        qBound(static_cast<double>(minA), action.currentA, static_cast<double>(maxA)));

    const uint phases = (m_charger->canSetPhaseCount() && action.phaseCount > 0)
                        ? qBound(1u, action.phaseCount, m_charger->phaseCount())
                        : m_charger->phaseCount();

    const auto issuer = (action.funding == LoadAction::Surplus)
                        ? ChargingAction::ChargingActionIssuerSurplusCharging
                        : ChargingAction::ChargingActionIssuerTimeRequirement;

    ChargingAction ca(action.chargingEnabled, clampedA, phases, issuer, false);
    m_parent->doExecuteChargingAction(m_charger, ca, now);  // now = temps de cycle (injectable)
    m_lastActionAt = now;

    LoadAction applied = action;
    applied.currentA   = clampedA;
    applied.phaseCount = phases;
    return applied;
}
