using InnovEnergy.Lib.Units.Power;
using static System.Math;

namespace InnovEnergy.Lib.Units.Composite;


public sealed class AcPower
{
    private AcPower(){}

    public required ApparentPower Apparent { get; init; } 
    public required ActivePower   Active   { get; init; } 
    public required ReactivePower Reactive { get; init; } 
    public required Angle         Phi      { get; init; } 
    public required Double        CosPhi   { get; init; } 
    
    public static AcPower FromActiveReactiveApparent(ActivePower activePower, ReactivePower reactivePower, ApparentPower apparentPower)
    {
        var q   = reactivePower.Value;
        var p   = activePower.Value;
        var s   = apparentPower.Value;
        var phi = Atan2(q, p);

        return new AcPower
        {
            Active   = p,
            Reactive = q,
            Apparent = s,
            Phi      = phi,
            CosPhi   = Cos(phi),
        };
    }
    
    public static AcPower FromActiveReactive(ActivePower activePower, ReactivePower reactivePower)
    {
        var q   = reactivePower.Value;
        var p   = activePower.Value;
        var s   = Sqrt(p * p + q * q);
        var phi = Atan2(q, p);

        return new AcPower
        {
            Active   = p,
            Reactive = q,
            Apparent = s,
            Phi      = phi,
            CosPhi   = Cos(phi),
        };
    }
    
    public static AcPower FromVoltageCurrentPhi(Voltage voltageRms, Current currentRms, Angle phi)
    {
        if (voltageRms < 0) throw new ArgumentException("RMS value cannot be negative", nameof(voltageRms));
        if (currentRms < 0) throw new ArgumentException("RMS value cannot be negative", nameof(currentRms));

        var cosPhi   = Cos(phi.Value);
        var apparent = voltageRms.Value * currentRms.Value;

        return new AcPower
        {
            Apparent = apparent,
            Active   = apparent * cosPhi,
            Reactive = apparent * Sin(phi.Value),
            Phi      = phi,
            CosPhi   = cosPhi
        };
    }

    public static AcPower SumOf(params AcPower[] phases)
    {
        var p = phases.Sum(l => l.Active.Value);
        var q = phases.Sum(l => l.Reactive.Value);
        var s = Sqrt(p * p + q * q);

        Angle phi = Atan2(q, p);

        return new AcPower
        {
            Apparent = s,
            Active   = p,
            Reactive = q,
            Phi      = phi,
            CosPhi   = Cos(phi.Value)
        };
    }
    
    public static AcPower Null => FromVoltageCurrentPhi(0, 0, 0);

    public static AcPower operator +(AcPower left, AcPower right) => FromActiveReactive
    (
        left.Active + right.Active,
        left.Reactive + right.Reactive
    );

    public static AcPower operator -(AcPower left, AcPower right) => FromActiveReactive
    (
        left.Active - right.Active,
        left.Reactive - right.Reactive   
    );
    
    public static AcPower operator -(AcPower p) => FromActiveReactive(-p.Active, p.Reactive);
    
    
    
    public override String ToString() => Active.ToString(); // TODO: show all
}