using System.Threading;
using System.Threading.Tasks;
using Cirno.Scripts.Enums;
using Godot;
using GTweens.Builders;
using GTweens.Tweens;
using GTweensGodot.Extensions;

namespace Cirno.Scripts.Components.FSM.Elevator;

public abstract partial class ElevatorMovementState : BaseState<ElevatorState, ElevatorProxy>
{
    [Export] public AudioStreamPlayer2D Sound { get; private set; } 
    
    protected GTween Tween;
    //protected Node2D OldPlayerParent;

    protected abstract Vector2 StartingPosition { get; }
    protected abstract Vector2 EndingPosition { get; }

    protected abstract ElevatorState EndState { get; }

    protected CharacterBody2D PlayerBody => MainObject.CachedPlayer?.StateMachine.MainObject;

    public override void EnterState()
    {
        Tween?.Kill();
        MainObject.SetPosition(StartingPosition);
        Move();
        Sound.Play();
    }

    public override void ExitState()
    {
        Tween?.Kill();
        RestorePlayerParent();
        Sound.Stop();
    }

    // public override void PhysicsProcessState(double delta)
    // {
    //     base.PhysicsProcessState(delta);
    //     MainObject.TopBody.SetPosition(MainObject.Top);
    // }

    private void RestorePlayerParent()
    {
        if (PlayerBody is null) return;
        PlayerBody.Reparent(PlayerBody.Owner);
        //OldPlayerParent = null;
        MainObject.CachedPlayer?.StateMachine.SetState(PlayerState.Active);
    }

    private void CatchPlayer()
    {
        if (PlayerBody is null) return;
        //OldPlayerParent = PlayerBody.GetParent<Node2D>();
        MainObject.CachedPlayer.StateMachine.SetState(PlayerState.Cutscene);
        PlayerBody.Reparent(MainObject);
    }

    private void Move()
    {
        // Grab player if in range
        CatchPlayer();

        _ = MovePlayerToCenter();
        
        //Ascend
        _ = PlayAnimation();
    }

    private async Task PlayAnimation()
    {
        Tween = GTweenSequenceBuilder.New()
            .Append(MainObject.TweenPosition(EndingPosition, MainObject.MovementTime))
            .Build();

        await Tween.PlayAsync(CancellationToken.None);

        StateMachine.SetState(EndState);
    }

    private async Task MovePlayerToCenter()
    {
        var tween = GTweenSequenceBuilder.New()
            .Append(PlayerBody.TweenPosition(MainObject.Position, 0.2f))
            .Build();
        
        await tween.PlayAsync(CancellationToken.None);
    }
}