using System;
using Godot;
using GodotStateCharts;

namespace Movementtests.systems;

public partial class WeaponSystem : RigidBody3D
{
    [Export(PropertyHint.Range, "0,100,1,or_greater")]
    public float ThrowForce { get; set; } = 1f;
    [Export(PropertyHint.Range, "0,0.2,0.01,or_greater")]
    public float StraightThrowDuration { get; set; } = 0.1f;
    
    private StateChart       _weaponState;
    public StateChartState  InHandState;
    public StateChartState  FlyingState;
    public StateChartState  PlantedState;
    
    private Node3D _head;
    private ShapeCast3D _dashCast3D;
    private Camera3D _camera;
    private TweenQueueSystem _tweenQueueSystem;
    
    private Transform3D _startTransform;

    private Vector3 _throwDirection;
    public Vector3 PlantLocation { get; set; }
    public Vector3 PlantNormal { get; set; }

    public void Init(Node3D head, Camera3D camera)
    {
        _head = head;
        _camera = camera;
        
        _weaponState = StateChart.Of(GetNode("StateChart"));
        InHandState = StateChartState.Of(GetNode("StateChart/Root/InHand"));
        FlyingState = StateChartState.Of(GetNode("StateChart/Root/Flying"));
        PlantedState = StateChartState.Of(GetNode("StateChart/Root/Planted"));
        
        _tweenQueueSystem = GetNode<TweenQueueSystem>("TweenQueueSystem");
        _tweenQueueSystem.Init(this);

        _startTransform = Transform;
        Freeze = true;

        BodyEntered += OnThrownWeaponReachesGround;
    }

    public void ThrowWeapon(Vector3 end, bool hasHit, Vector3 collisionLocation, Vector3 collisionNormal)
    {
        _weaponState.SendEvent("throw");
        
        _throwDirection = (end - GlobalPosition).Normalized();
        PlantLocation = collisionLocation;
        PlantNormal = collisionNormal;
        LookAt(end);
    
        var tween = _tweenQueueSystem.TweenToLocation(new TweenQueueSystem.TweenInputs(end, StraightThrowDuration));
        if (hasHit)
            tween.Finished += PlantWeaponInWall;
        else
            tween.Finished += ThrowWeaponOnCurve;
    }

    public void ThrowWeaponOnCurve()
    {
        Freeze = false;
        ApplyImpulse(_throwDirection * ThrowForce);
    }

    public void PlantWeaponInWall()
    {
        _weaponState.SendEvent("plant");
        Freeze = true;
        GlobalPosition = PlantLocation;
        LookAt(GlobalTransform.Origin + PlantNormal, Vector3.Up, true);
    }

    public void OnThrownWeaponReachesGround(Node other)
    {
        PlantWeaponInWall();
    }

    public void ResetWeapon()
    {
        _weaponState.SendEvent("recover");
        Transform = _startTransform;
        Freeze = true;
    }
    
    public override void _IntegrateForces(PhysicsDirectBodyState3D state)
    {
        base._IntegrateForces(state);
        
        if (!Freeze && state.GetContactCount() > 0)
        {
            PlantLocation = state.GetContactLocalPosition(0);
            PlantNormal = state.GetContactLocalNormal(0);
        }
    }

    public bool IsPlantedUnderPlatform()
    {
        return PlantedState.Active && GlobalRotation.X > 1 && Math.Abs(GlobalRotation.Y) > 1;
    }

    public bool IsPlantedInWall()
    {
        return PlantedState.Active && Math.Abs(GlobalRotation.X) + Math.Abs(GlobalRotation.Z) < 0.3;
    }
}