using System;
using Cirno.Scripts;
using Cirno.Scripts.Utils;
using Godot;
using Godot.Collections;

namespace Cirno._3D.TrenchBroom.EntityScripts.Solid;

[Tool]
public partial class FuncMove : AnimatableBody3D, IActivable
{
    [Export] public string TargetName { get; private set; }

    [Export] public Array<Vector3> MovePos { get; set; } = [Vector3.Zero, Vector3.Zero];
    [Export] public Vector3 MoveRot { get; set; } = Vector3.Zero;

    [Export] public float Speed { get; set; } = 3.0f;

    public enum MoveStates
    {
        READY,
        MOVE
    }

    private MoveStates _state = MoveStates.READY;
    private float _moveProgress = 0.0f;
    private float _moveProgressTarget = 0.0f;


    public void _func_godot_apply_properties(Dictionary<string, Variant> props)
    {
        TargetName = props["targetname"].AsString();
        MovePos[1] = QuakeTools.IdVecToGodotVec(props["move_pos"]) * QuakeTools.InverseScale;

        if (props["move_rot"].Obj is Vector3 rotVec)
        {
            MoveRot = new Vector3(Mathf.DegToRad(rotVec.X), Mathf.DegToRad(rotVec.Y), Mathf.DegToRad(rotVec.Z));
        }

        Speed = props["speed"].AsSingle();

        // if (props.TryGetValue("activationtype", out var type))
        // {
        // 	var t = Enum.TryParse(type, true, out ActivationType activationType);
        // 	if (t)
        // 	{
        // 		ActivationType = activationType;
        // 	}
        // }
        // TODO: Oneshot
    }

    public void MoveForward()
    {
        _moveProgressTarget = 1.0f;
    }

    public void Use()
    {
        MoveForward();
    }
    
    public void MoveReverse()
    {
        _moveProgressTarget = 0.0f;
    }

    public bool Activate(ActivationType activationType = ActivationType.Toggle)
    {
        switch (activationType)
        {
            case ActivationType.Toggle:
            case ActivationType.Use:
                Toggle();
                break;
            case ActivationType.Enable:
            case ActivationType.Open:
                MoveForward();
                break;
            case ActivationType.Disable:
            case ActivationType.Close:
                MoveReverse();
                break;
      
            case ActivationType.Destroy:
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(activationType), activationType, null);
        }

        return true;
    }

    public void Toggle()
    {
        if (_moveProgressTarget > 0.0)
        {
            MoveReverse();
        }
        else
        {
            MoveForward();
        }
    }

    public FuncMove()
    {
        AddToGroup("func_move");
        SyncToPhysics = false;
    }

    public override void _Ready()
    {
        if (Engine.IsEditorHint()) return;

        if (!string.IsNullOrWhiteSpace(TargetName))
        {
            this.AddToGroup(TargetName);
        }

        MovePos[0] = Position;
        MovePos[1] += MovePos[0];
        if (Speed > 0.0f)
        {
            Speed = 1.0f / Speed;
        }
    }

    public override void _PhysicsProcess(double delta)
    {
        if (Engine.IsEditorHint()) return;

        if (_moveProgress == _moveProgressTarget)
        {
            return;
        }

        if (_moveProgress < _moveProgressTarget)
        {
            _moveProgress = Mathf.Min(_moveProgress + (float)(Speed * delta), _moveProgressTarget);
        }
        else if (_moveProgress > _moveProgressTarget)
        {
            _moveProgress = Mathf.Max(_moveProgress - (float)(Speed * delta), _moveProgressTarget);
        }

        if (MovePos[0] != MovePos[1])
        {
            Position = MovePos[0].Lerp(MovePos[1], _moveProgress);
        }

        if (MoveRot != Vector3.Zero)
        {
            Rotation = Vector3.Zero.Lerp(MoveRot, _moveProgress);
        }
    }
}