using System;
using Controller.Bicycle;
using Sensors;
using Sensors.ANT;
using Sensors.Polar;
using Tracking;
using UnityEngine;
using UnityEngine.Serialization;

namespace Controller
{
    [Serializable]
    public struct PolarRotationMapping
    {
        public float maxRight;
        public float center;
    }

    [Serializable]
    public struct FrontWheelTrackerConfig
    {
        public FrontWheelTracker frontWheelTracker;
        public float multiplicator;

        public float AdjustedRotation => frontWheelTracker.SteerRotation * multiplicator;
    }

    [RequireComponent(typeof(IBicycleController))]
    public class SensorBikeController : MonoBehaviour
    {
        public PolarRotationMapping polarRotationMapping;

        public SpeedSensorConfig speedSensorConfig;
        public PolarSensorConfig polarSensorConfig;
        public FrontWheelTrackerConfig frontWheelTrackerConfig;

        public bool steer = true;
        public bool accelerate = true;
        public bool lean = true;

        private IBicycleController bicycleController;
        private BikeSensorData sensorData;
        private float leanFactor;
        private bool isFrontWheelTrackerNotNull;

        private void Start()
        {
            isFrontWheelTrackerNotNull = frontWheelTrackerConfig.frontWheelTracker != null;
            bicycleController = GetComponent<IBicycleController>();
            sensorData = BikeSensorData.Instance;
            sensorData.StartListening(polarSensorConfig: polarSensorConfig, speedSensorConfig: speedSensorConfig);
            leanFactor = 90f / (polarRotationMapping.maxRight - polarRotationMapping.center);
        }

        private void Update()
        {
            var speedData = sensorData.SpeedData;
            var polarData = sensorData.PolarData;

            if (speedData != null && accelerate)
            {
                SetSpeed(speedData.Value);
            }

            if (isFrontWheelTrackerNotNull && steer)
            {
                SetSteer();
            }

            if (polarData != null && lean)
            {
                SetLeaningAngle(polarData.Value);
            }
        }

        private void SetSteer()
        {
            bicycleController.CurrentSteerAngle =
                frontWheelTrackerConfig.AdjustedRotation;
        }

        private void OnDestroy()
        {
            sensorData?.Dispose();
        }

        private void SetLeaningAngle(PolarSensorData polarData)
        {
            bicycleController.CurrentLeaningAngle = (polarData.Acc.y - polarRotationMapping.center) * leanFactor;
        }

        private void SetSpeed(SpeedSensorData speedData)
        {
            bicycleController.CurrentSpeed = speedData.Speed;
        }
    }
}