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

public partial class CheckpointAnimation : Node2D, IActivable
{
    [Export] public AnimatedSprite2D Sprite { get; private set; }
    [Export] public Label Label { get; private set; }
    
    [Export] public AudioStreamPlayer2D Sound { get; private set; }

    [Export] public StringName ClosedAnimationName { get; private set; } = "Closed";
    [Export] public StringName OpenAnimationName { get; private set; } = "Open";

    [Export] public Vector2 LabelStartPosition { get; private set; } = new Vector2(0, 0);
    [Export] public Vector2 LabelEndPosition { get; private set; } = new Vector2(0, 16);

    [Export] public float LabelAnimationTime { get; private set; } = 0.5f;

    [Export] public float DoorCloseTime { get; private set; } = 1.5f;

    private GTween _tween;

    private CancellationTokenSource _cts;
    
    public override void _Ready()
    {
        Sprite.Play(ClosedAnimationName);
        Label.Hide();
    }

    public bool Activate(ActivationType activationType = ActivationType.Toggle)
    {
        // Cancel previous token
        _cts?.Cancel();
        _cts?.Dispose();

        // Create new token source
        _cts = new CancellationTokenSource();
        
        // Start new animation with the new token
        _ = AnimateAsync(_cts.Token);

        return true;
    }

    private async Task AnimateAsync(CancellationToken cancellationToken)
    {
        try
        {
            //_tween?.Complete();
            if (_tween != null)
            {
                await _tween.AwaitCompleteOrKill(cancellationToken);
            }

            Sound.Play();
            
            Label.Show();
            Label.SetPosition(LabelStartPosition);
            Sprite.Play(OpenAnimationName);
            
            //Sprite.Play(ClosedAnimationName);
            _tween = GTweenSequenceBuilder.New()
                // .AppendCallback(() =>
                // {
                //     Sprite.Play(OpenAnimationName);
                //     Label.SetPosition(LabelStartPosition);
                //     Label.Show();
                // })
                // .AppendCallback(() => Sprite.Play(OpenAnimationName))
                // .AppendCallback(() => Label.SetPosition(LabelStartPosition))
                // .AppendCallback(() => Label.Show())
                .Append(Label.TweenPositionY(LabelEndPosition.Y, LabelAnimationTime))
                .AppendTime(DoorCloseTime)
                .AppendCallback(() => Label.Hide())
                .AppendCallback(() => Sprite.Play(ClosedAnimationName))
                .Build();

            _tween.SetEasing(Easing.OutBounce);
            
            await _tween.PlayAsync(cancellationToken);
        }
        catch (OperationCanceledException)
        {
            GD.Print("Animation was cancelled.");
            // Optional cleanup here
        }
        catch (Exception e)
        {
            GD.PrintErr($"Unexpected error during animation: {e}");
            throw;
        }
    }
}