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

#include <QDateTime>
#include <QList>
#include <QString>
#include "loaddescriptor.h"

// Structures miroirs de OPTIMIZER_PROTOCOL.md §5 (noms de champs identiques).

/*! \brief Paramètres fixes du site (contrat réseau, limite par phase). */
struct SurplusSite {
    double        contractedPowerW = 0;    //!< Puissance souscrite (W).
    QList<double> phaseLimitA;             //!< Limite par phase (A) : [63, 63, 63].
};

/*! \brief Mesures du compteur principal (rootmeter). */
struct SurplusMeter {
    double        importW = 0;   //!< Puissance importée depuis le réseau (W, ≥ 0).
    double        exportW = 0;   //!< Puissance exportée vers le réseau (W, ≥ 0).
    QList<double> perPhaseA;     //!< Courant par phase (A).
};

/*! \brief Production PV courante. */
struct SurplusPv {
    double currentW = 0;  //!< Puissance PV mesurée (W, ≥ 0).
};

/*! \brief État courant du système de stockage (batterie). */
struct SurplusBattery {
    bool   present           = false;
    double socPercent        = 0;
    double powerW            = 0;    //!< Positif = charge, négatif = décharge.
    double capacityWh        = 0;
    int    reserveSocPercent = 0;
    double maxChargeW        = 0;
    double maxDischargeW     = 0;
};

/*! \brief Entrée tarifaire (créneau HP/HC ou spot market). */
struct TariffEntry {
    QDateTime from;
    QString   label;          //!< "HP", "HC", "Tempo-Rouge", ...
    double    priceCtkWh = 0; //!< Prix en ct€/kWh.
};

/*! \brief Contexte tarifaire : créneau courant + prochains créneaux. */
struct SurplusTariff {
    QString            provider;
    TariffEntry        current;
    QList<TariffEntry> next;   //!< Créneaux suivants, ordre chronologique.
};

/*! \brief Télémétrie d'une charge dans le contexte §5 loads[].telemetry. */
struct LoadContextTelemetry {
    double    currentPowerW = 0;   //!< Puissance mesurée (W).
    // --- evcharger ---
    bool      pluggedIn  = false;
    bool      charging   = false;
    double    sessionWh  = 0;      //!< Énergie chargée dans la session courante (Wh).
    // --- relay-stages ---
    int       stage      = 0;
    //! Fenêtre de paliers autorisée MAINTENANT par les verrous (calculée au temps de cycle).
    //! Le scheduler y borne son choix : minStage = plancher (verrou minOn, puissance
    //! engagée non-coupable) ; maxStage = plafond (verrou minOff, redémarrage interdit).
    int       minStage   = 0;
    int       maxStage   = 0;
    // --- sg-ready ---
    int       state      = 0;
    // --- battery / electricvehicle ---
    double    socPercent = 0;
    QDateTime lastSwitch;          //!< Dernier changement d'état.
};

/*! \brief Données apprises par l'optimiseur §8 (renvoyées pour persistance). */
struct LoadLearned {
    double dailyEnergyWh = 0;
    //! Confiance 0–1 ; < 0.7 = "profil en apprentissage".
    double confidence    = 0.0;
};

/*!
 * \brief Entrée loads[] du SurplusContext envoyé au scheduler.
 * Construit par l'arbitre depuis ILoadAdapter::descriptor() + toLoadContext().
 */
struct LoadContext {
    QString              id;
    QString              adapter;   //!< "evcharger"|"relay-stages"|"sg-ready"|"battery".
    QString              label;
    int                  priority = 0;
    LoadDeclared         declared;
    LoadLearned          learned;
    LoadContextTelemetry telemetry;
    LoadNeeds            needs;
    LoadLimits           limits;
};

/*!
 * \brief Contexte complet transmis au scheduler à chaque cycle (OPTIMIZER_PROTOCOL §5).
 *
 * \invariant \c timestamp correspond à l'instant du début du cycle.
 * \invariant \c pv.currentW est la PV mesurée brute — JAMAIS le net après pilotage
 *   (AGENTS invariant 8 : pas de boucle de feedback).
 */
struct SurplusContext {
    QDateTime          timestamp;
    SurplusSite        site;
    SurplusMeter       meter;
    SurplusPv          pv;
    SurplusBattery     battery;
    QList<LoadContext>  loads;
    SurplusTariff      tariff;
    // forecast : opaque, transmis tel quel si présent — réservé V2
};
