/*
 * Copyright (C) 2007-2024 C# Port
 * Original Copyright (C) 2007-2018 Siemens AG
 *
 * Exact V2G types and enumerations - byte-compatible with OpenV2G ISO1 implementation
 * Based on iso1EXIDatatypes.h
 */

using System;

namespace V2GDecoderNet.V2G
{
    /// <summary>
    /// Response code enumeration - exact match to iso1responseCodeType
    /// 5-bit encoding (0-31)
    /// </summary>
    public enum ResponseCodeType
    {
        OK = 0,
        OK_NewSessionEstablished = 1,
        OK_OldSessionJoined = 2,
        OK_CertificateExpiresSoon = 3,
        FAILED = 4,
        FAILED_SequenceError = 5,
        FAILED_ServiceIDInvalid = 6,
        FAILED_UnknownSession = 7,
        FAILED_ServiceSelectionInvalid = 8,
        FAILED_PaymentSelectionInvalid = 9,
        FAILED_CertificateExpired = 10,
        FAILED_SignatureError = 11,
        FAILED_NoCertificateAvailable = 12,
        FAILED_CertChainError = 13,
        FAILED_ChallengeInvalid = 14,
        FAILED_ContractCanceled = 15,
        FAILED_WrongChargeParameter = 16,
        FAILED_PowerDeliveryNotApplied = 17,
        FAILED_TariffSelectionInvalid = 18,
        FAILED_ChargingProfileInvalid = 19,
        FAILED_MeteringSignatureNotValid = 20,
        FAILED_NoChargeServiceSelected = 21,
        FAILED_WrongEnergyTransferMode = 22,
        FAILED_ContactorError = 23,
        FAILED_CertificateNotAllowedAtThisEVSE = 24,
        FAILED_CertificateRevoked = 25
    }

    /// <summary>
    /// Unit symbol enumeration - exact match to iso1unitSymbolType
    /// 3-bit encoding (0-7)
    /// </summary>
    public enum UnitSymbolType
    {
        h = 0,    // hours
        m = 1,    // meters
        s = 2,    // seconds
        A = 3,    // amperes
        V = 4,    // volts
        W = 5,    // watts
        Wh = 6    // watt-hours
    }

    /// <summary>
    /// EVSE isolation status enumeration - exact match to iso1isolationLevelType
    /// 3-bit encoding (0-7)
    /// </summary>
    public enum IsolationLevelType
    {
        Invalid = 0,
        Valid = 1,
        Warning = 2,
        Fault = 3,
        No_IMD = 4
    }

    /// <summary>
    /// EVSE status code enumeration - exact match to iso1DC_EVSEStatusCodeType
    /// 4-bit encoding (0-15)
    /// </summary>
    public enum DC_EVSEStatusCodeType
    {
        EVSE_NotReady = 0,
        EVSE_Ready = 1,
        EVSE_Shutdown = 2,
        EVSE_UtilityInterruptEvent = 3,
        EVSE_IsolationMonitoringActive = 4,
        EVSE_EmergencyShutdown = 5,
        EVSE_Malfunction = 6,
        Reserved_8 = 7,
        Reserved_9 = 8,
        Reserved_A = 9,
        Reserved_B = 10,
        Reserved_C = 11
    }

    /// <summary>
    /// EVSE notification enumeration - exact match to iso1EVSENotificationType
    /// 2-bit encoding (0-3)
    /// </summary>
    public enum EVSENotificationType
    {
        None = 0,
        StopCharging = 1,
        ReNegotiation = 2
    }

    /// <summary>
    /// Physical value structure - exact match to iso1PhysicalValueType
    /// </summary>
    public class PhysicalValueType
    {
        /// <summary>
        /// Power-of-10 multiplier (-3 to +3) - encoded as 3-bit (value + 3)
        /// </summary>
        public sbyte Multiplier { get; set; }

        /// <summary>
        /// Unit symbol - encoded as 3-bit enumeration
        /// </summary>
        public UnitSymbolType Unit { get; set; }

        /// <summary>
        /// Actual value - encoded as 16-bit signed integer
        /// </summary>
        public short Value { get; set; }

        public PhysicalValueType()
        {
            Multiplier = 0;
            Unit = (UnitSymbolType)0;  // Match VC2022 uninitialized memory behavior
            Value = 0;
        }

        public PhysicalValueType(sbyte multiplier, UnitSymbolType unit, short value)
        {
            Multiplier = multiplier;
            Unit = unit;
            Value = value;
        }
    }

    /// <summary>
    /// DC EVSE status structure - exact match to iso1DC_EVSEStatusType
    /// </summary>
    public class DC_EVSEStatusType
    {
        /// <summary>
        /// Notification max delay - 16-bit unsigned integer
        /// </summary>
        public ushort NotificationMaxDelay { get; set; }

        /// <summary>
        /// EVSE notification - 2-bit enumeration
        /// </summary>
        public EVSENotificationType EVSENotification { get; set; }

        /// <summary>
        /// EVSE isolation status - 3-bit enumeration (optional)
        /// </summary>
        public IsolationLevelType EVSEIsolationStatus { get; set; }

        /// <summary>
        /// Optional flag for EVSEIsolationStatus
        /// </summary>
        public bool EVSEIsolationStatus_isUsed { get; set; }

        /// <summary>
        /// EVSE status code - 4-bit enumeration
        /// </summary>
        public DC_EVSEStatusCodeType EVSEStatusCode { get; set; }

        public DC_EVSEStatusType()
        {
            NotificationMaxDelay = 0;
            EVSENotification = EVSENotificationType.None;
            EVSEIsolationStatus = IsolationLevelType.Invalid;
            EVSEIsolationStatus_isUsed = false;
            EVSEStatusCode = DC_EVSEStatusCodeType.EVSE_NotReady;
        }
    }

    /// <summary>
    /// Meter info structure - exact match to iso1MeterInfoType
    /// </summary>
    public class MeterInfoType
    {
        public string MeterID { get; set; } = "";
        public ulong MeterReading { get; set; }
        public sbyte SigMeterReading { get; set; }
        public string MeterStatus { get; set; } = "";
        public long TMeter { get; set; }
    }

    /// <summary>
    /// Current demand response structure - exact match to iso1CurrentDemandResType
    /// Grammar states 317-330
    /// </summary>
    public class CurrentDemandResType
    {
        /// <summary>
        /// Response code - 5-bit enumeration (Grammar state 317)
        /// </summary>
        public ResponseCodeType ResponseCode { get; set; }

        /// <summary>
        /// DC EVSE status - complex type (Grammar state 318)
        /// </summary>
        public DC_EVSEStatusType DC_EVSEStatus { get; set; }

        /// <summary>
        /// EVSE present voltage - PhysicalValue (Grammar state 319)
        /// </summary>
        public PhysicalValueType EVSEPresentVoltage { get; set; }

        /// <summary>
        /// EVSE present current - PhysicalValue (Grammar state 320)
        /// </summary>
        public PhysicalValueType EVSEPresentCurrent { get; set; }

        /// <summary>
        /// Current limit achieved flag (Grammar state 321)
        /// </summary>
        public bool EVSECurrentLimitAchieved { get; set; }

        /// <summary>
        /// Voltage limit achieved flag (Grammar state 322)
        /// </summary>
        public bool EVSEVoltageLimitAchieved { get; set; }

        /// <summary>
        /// Power limit achieved flag (Grammar state 323)
        /// </summary>
        public bool EVSEPowerLimitAchieved { get; set; }

        /// <summary>
        /// Maximum voltage limit (Optional - Grammar state 324 choice 0 → 325)
        /// </summary>
        public PhysicalValueType EVSEMaximumVoltageLimit { get; set; }
        public bool EVSEMaximumVoltageLimit_isUsed { get; set; }

        /// <summary>
        /// Maximum current limit (Optional - Grammar state 324 choice 1 → 326)
        /// </summary>
        public PhysicalValueType EVSEMaximumCurrentLimit { get; set; }
        public bool EVSEMaximumCurrentLimit_isUsed { get; set; }

        /// <summary>
        /// Maximum power limit (Optional - Grammar state 324 choice 2 → 327)
        /// </summary>
        public PhysicalValueType EVSEMaximumPowerLimit { get; set; }
        public bool EVSEMaximumPowerLimit_isUsed { get; set; }

        /// <summary>
        /// EVSE ID string (37 characters max - Grammar state 324 choice 3 → 328)
        /// </summary>
        public string EVSEID { get; set; } = "";

        /// <summary>
        /// SA schedule tuple ID - 8-bit (value-1) (Grammar state 328)
        /// </summary>
        public byte SAScheduleTupleID { get; set; }

        /// <summary>
        /// Meter info (Optional - Grammar state 329 choice 0 → 330)
        /// </summary>
        public MeterInfoType MeterInfo { get; set; }
        public bool MeterInfo_isUsed { get; set; }

        /// <summary>
        /// Receipt required flag (Optional - Grammar state 329 choice 1 → END)
        /// </summary>
        public bool ReceiptRequired { get; set; }
        public bool ReceiptRequired_isUsed { get; set; }

        public CurrentDemandResType()
        {
            ResponseCode = ResponseCodeType.OK;
            DC_EVSEStatus = new DC_EVSEStatusType();
            EVSEPresentVoltage = new PhysicalValueType();
            EVSEPresentCurrent = new PhysicalValueType();
            EVSECurrentLimitAchieved = false;
            EVSEVoltageLimitAchieved = false;
            EVSEPowerLimitAchieved = false;
            
            EVSEMaximumVoltageLimit = new PhysicalValueType();
            EVSEMaximumVoltageLimit_isUsed = false;
            EVSEMaximumCurrentLimit = new PhysicalValueType();
            EVSEMaximumCurrentLimit_isUsed = false;
            EVSEMaximumPowerLimit = new PhysicalValueType();
            EVSEMaximumPowerLimit_isUsed = false;
            
            EVSEID = "";
            SAScheduleTupleID = 1;
            
            MeterInfo = new MeterInfoType();
            MeterInfo_isUsed = false;
            ReceiptRequired = false;
            ReceiptRequired_isUsed = false;
        }
    }

    /// <summary>
    /// Current demand request structure - exact match to iso1CurrentDemandReqType
    /// Grammar states 273-280
    /// </summary>
    public class CurrentDemandReqType
    {
        /// <summary>
        /// DC EV status information (Mandatory - Grammar state 273)
        /// </summary>
        public DC_EVStatusType DC_EVStatus { get; set; }

        /// <summary>
        /// EV target current (Mandatory - Grammar state 274)
        /// </summary>
        public PhysicalValueType EVTargetCurrent { get; set; }

        /// <summary>
        /// EV maximum voltage limit (Optional - Grammar state 275 choice 0)
        /// </summary>
        public PhysicalValueType EVMaximumVoltageLimit { get; set; }
        public bool EVMaximumVoltageLimit_isUsed { get; set; }

        /// <summary>
        /// EV maximum current limit (Optional - Grammar state 275 choice 1)
        /// </summary>
        public PhysicalValueType EVMaximumCurrentLimit { get; set; }
        public bool EVMaximumCurrentLimit_isUsed { get; set; }

        /// <summary>
        /// EV maximum power limit (Optional - Grammar state 275 choice 2)
        /// </summary>
        public PhysicalValueType EVMaximumPowerLimit { get; set; }
        public bool EVMaximumPowerLimit_isUsed { get; set; }

        /// <summary>
        /// Bulk charging complete flag (Optional - Grammar state 275 choice 3)
        /// </summary>
        public bool BulkChargingComplete { get; set; }
        public bool BulkChargingComplete_isUsed { get; set; }

        /// <summary>
        /// Charging complete flag (Mandatory - no _isUsed flag in VC2022)
        /// </summary>
        public bool ChargingComplete { get; set; }

        /// <summary>
        /// Remaining time to full SoC (Optional)
        /// </summary>
        public PhysicalValueType RemainingTimeToFullSoC { get; set; }
        public bool RemainingTimeToFullSoC_isUsed { get; set; }

        /// <summary>
        /// Remaining time to bulk SoC (Optional)
        /// </summary>
        public PhysicalValueType RemainingTimeToBulkSoC { get; set; }
        public bool RemainingTimeToBulkSoC_isUsed { get; set; }

        /// <summary>
        /// EV target voltage (Mandatory - no _isUsed flag in VC2022)
        /// </summary>
        public PhysicalValueType EVTargetVoltage { get; set; }

        public CurrentDemandReqType()
        {
            DC_EVStatus = new DC_EVStatusType();
            EVTargetCurrent = new PhysicalValueType();
            EVMaximumVoltageLimit = new PhysicalValueType();
            EVMaximumVoltageLimit_isUsed = false;
            EVMaximumCurrentLimit = new PhysicalValueType();
            EVMaximumCurrentLimit_isUsed = false;
            EVMaximumPowerLimit = new PhysicalValueType();
            EVMaximumPowerLimit_isUsed = false;
            BulkChargingComplete = false;
            BulkChargingComplete_isUsed = false;
            ChargingComplete = false;
            RemainingTimeToFullSoC = new PhysicalValueType();
            RemainingTimeToFullSoC_isUsed = false;
            RemainingTimeToBulkSoC = new PhysicalValueType();
            RemainingTimeToBulkSoC_isUsed = false;
            EVTargetVoltage = new PhysicalValueType();
        }
    }

    /// <summary>
    /// DC EV status structure - exact match to iso1DC_EVStatusType
    /// </summary>
    public class DC_EVStatusType
    {
        public bool EVReady { get; set; }
        public int EVErrorCode { get; set; } // 4-bit enumeration
        public int EVRESSSOC { get; set; } // 7-bit (0-100)

        public DC_EVStatusType()
        {
            EVReady = false;
            EVErrorCode = 0;
            EVRESSSOC = 0;
        }
    }

    /// <summary>
    /// Universal message body type - matches iso1BodyType
    /// </summary>
    public class BodyType
    {
        // All possible message types (only one will be used per message)
        public CurrentDemandReqType CurrentDemandReq { get; set; }
        public bool CurrentDemandReq_isUsed { get; set; }
        
        public CurrentDemandResType CurrentDemandRes { get; set; }
        public bool CurrentDemandRes_isUsed { get; set; }

        public BodyType()
        {
            CurrentDemandReq = new CurrentDemandReqType();
            CurrentDemandReq_isUsed = false;
            CurrentDemandRes = new CurrentDemandResType();
            CurrentDemandRes_isUsed = false;
        }
    }

    /// <summary>
    /// V2G Message envelope structure
    /// </summary>
    public class V2GMessageExact
    {
        public string SessionID { get; set; } = "";
        public BodyType Body { get; set; }

        public V2GMessageExact()
        {
            Body = new BodyType();
        }
    }
}