using Sandbox.Citizen;
using Sandbox.Network;
using ShrimpleCharacterController;

public sealed class Kal : Component
{
	[RequireComponent] private ShrimpleCharacterController.ShrimpleCharacterController Controller { get; set; }
	[RequireComponent] private AnimationHelper AnimationHelper { get; set; }
    public SkinnedModelRenderer Renderer { get; set; } 
    [Property] public GameObject Body { get; set; } 
    public GameObject Camera { get; set; }
    
    [Property] [Range(1f, 200f, 1f)] public float CamOffsetX { get; set; } 
    [Property] [Range(1f, 200f, 1f)] public float CamOffsetZ { get; set; }
    [Property] [Range(50f, 200f, 10f)] public float WalkSpeed { get; set; } = 100f;
    [Property] [Range(100f, 500f, 20f)] public float RunSpeed { get; set; } = 300f;
    [Property] [Range(25f, 100f, 5f)] public float DuckSpeed { get; set; } = 50f;
    [Property] [Range(200f, 500f, 20f)] public float JumpStrength { get; set; } = 350f;
    
    [Sync] public Angles EyeAngles { get; set; }
    // [Sync] public bool IsDucking { get; set; }
    // [Sync] public bool IsRunning { get; set; }

    protected override void OnStart() 
    {
        base.OnStart();

        Controller = Components.Get<ShrimpleCharacterController.ShrimpleCharacterController>();
        AnimationHelper = Components.Get<AnimationHelper>();

        if ( !Network.IsOwner ) return;

        Renderer = Components.Get<SkinnedModelRenderer>(FindMode.EverythingInSelfAndDescendants);
        Camera = Scene.Camera.GameObject;
        
        Camera.SetParent(GameObject);
        var cameraComponent = Camera.Components.Create<CameraComponent>();
        cameraComponent.ZFar = 32768f;
    }

    protected override void OnFixedUpdate()
    {
        base.OnFixedUpdate();
        
        if ( Network.IsOwner )
        {
	        var wishDirection = Input.AnalogMove.Normal * Rotation.FromYaw( EyeAngles.yaw );
	        var IsDucking = Input.Down( "Duck" );
	        var IsRunning = Input.Down( "Run" );
	        var wishSpeed = IsDucking ? DuckSpeed :
		        IsRunning ? RunSpeed : WalkSpeed;

	        Controller.WishVelocity = wishDirection * wishSpeed;
	        
	        Controller.Move();

	        if ( Input.Pressed( "Jump" ) && Controller.IsOnGround )
	        {
		        Controller.Punch( Vector3.Up * JumpStrength );
		        AnimationHelper.TriggerJump();
	        }
	        
	        if ( !AnimationHelper.IsValid() ) return;
	        
	        AnimationHelper.DuckLevel = IsDucking ? 1f : 0f;
        }
        
        Log.Info( AnimationHelper.HeadWeight );
        
        AnimationHelper.WithWishVelocity(Controller.WishVelocity);
        AnimationHelper.WithVelocity(Controller.Velocity);
        AnimationHelper.IsGrounded = Controller.IsOnGround;
    }

    protected override void OnUpdate()
    {
        base.OnUpdate();

        if ( Network.IsOwner )
        {
	        EyeAngles += Input.AnalogLook;
	        EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -90f, 70f));
	        // Renderer.WorldRotation = Rotation.Slerp(Renderer.WorldRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 5f);
	        var cameraOffset = Vector3.Up * CamOffsetZ + Vector3.Backward * CamOffsetX;
	        
			Camera.WorldRotation = EyeAngles.ToRotation();
	        Camera.LocalPosition = cameraOffset * Camera.WorldRotation;
        }
        
        RotateBody();
    }
    
    void RotateBody()
    {
	    if(Body is null) return;

	    var targetAngle = new Angles(0, EyeAngles.yaw, 0).ToRotation();
	    
	    float rotateDifference = Body.WorldRotation.Distance(targetAngle);

	    if(rotateDifference > 30f || Controller.Velocity.Length > 10f)
	    {
		    Body.WorldRotation = Rotation.Lerp(Body.WorldRotation, targetAngle, Time.Delta * 2f);
	    }
    }
}