namespace RobotNet.RobotManager.Services.Simulation;

public class VelocityController(VisualizationService Visualization)
{
    private double Acceleration = 2;
    private double Deceleration = 10;
    private double AngularVelLeft;
    private double AngularVelRight;
    private double SampleTime = 0.05;

    public VelocityController WithAcceleration(double acc)
    {
        Acceleration = acc;
        return this;
    }

    public VelocityController WithDeceleration(double dec)
    {
        Deceleration = dec;
        return this;
    }

    public VelocityController WithSampleTime(double time)
    {
        SampleTime = time;
        return this;
    }

    private (double angularVelLeft, double angularVelRight) AccelerationCalculator(double wL, double wR, double wL_Current, double wR_Current)
    {
        var angularVelLeft = wL_Current;
        var angularVelRight = wR_Current;
        if (wL_Current == 0 || wL / wL_Current < 0)
        {
            if (wL != 0) angularVelLeft += wL / Math.Abs(wL) * Acceleration;
            else angularVelLeft = wL;
        }
        else
        {
            if (Math.Abs(wL) - Math.Abs(wL_Current) > Acceleration) angularVelLeft += Acceleration * wL_Current / Math.Abs(wL_Current);
            else if (Math.Abs(wL_Current) - Math.Abs(wL) > Deceleration) angularVelLeft -= Deceleration * wL_Current / Math.Abs(wL_Current);
            else angularVelLeft = wL;
        }

        if (wR_Current == 0 || wR / wR_Current < 0)
        {
            if (wR != 0) angularVelRight += wR / Math.Abs(wR) * Acceleration;
            else angularVelRight = wR;
        }
        else
        {
            if (Math.Abs(wR) - Math.Abs(wR_Current) > Acceleration) angularVelRight += Acceleration * wR_Current / Math.Abs(wR_Current);
            else if (Math.Abs(wR_Current) - Math.Abs(wR) > Deceleration) angularVelRight -= Deceleration * wR_Current / Math.Abs(wR_Current);
            else angularVelRight = wR;
        }

        if (Math.Abs(angularVelLeft) > Math.Abs(wL)) angularVelLeft = wL;
        if (Math.Abs(angularVelRight) > Math.Abs(wR)) angularVelRight = wR;
        return (angularVelLeft, angularVelRight);
    }

    public bool SetSpeed(double angularVelLeft, double angularVelRight)
    {
        (AngularVelLeft, AngularVelRight) = AccelerationCalculator(angularVelLeft, angularVelRight, AngularVelLeft, AngularVelRight);
        //Console.WriteLine($"AngularVelLeft = {AngularVelLeft:0.####}, AngularVelRight = {AngularVelRight:0.####}");
        _ = Visualization.UpdatePosition(AngularVelLeft, AngularVelRight, SampleTime);
        return true;
    }

    public void Stop()
    {
        (AngularVelLeft, AngularVelRight) = (0, 0);
        _ = Visualization.UpdatePosition(AngularVelLeft, AngularVelRight, SampleTime);
    }
}
