using System.Threading.Tasks;
using Cirno.Scripts.AttackPatterns;
using Cirno.Scripts.Resources;
using Cirno.Scripts.Resources.ScriptableBullets;
using Cirno.Scripts.UI;
using Godot;
using Godot.Collections;

namespace Cirno.Scripts.Actors;

public partial class Boss : Enemy, IActivable, IScriptHost
{
    [Export] public string BossName { get; private set; }
    //[Export] private Array<BossPhase> Phases;
    [Export] public BossScript BossScript { get; set; }
    //[Export] private PackedScene BossHudPrefab;
    [Export] public Vector2 BossPhaseAnimationStartingPosition = new(180, 10);
    
    private int currentPhaseIndex = 0;

    private bool _started = false;
    private bool _waiting = false;
    
    private Vector2 _homePosition;
    public Vector2 HomePosition => _homePosition;
    public CharacterBody2D Body => this;
    public Node2D ParentObject => this;
    private BossPhase CurrentPhase => BossScript.Phases[currentPhaseIndex];

    private Marker2D _cameraMarker;

    [Export]
    public Vector2 CameraOffset = Vector2.Zero;

    private TextureRect _animationTextureRect;
    
    //[Export] private Texture2D _bossPortraitTexture;

    private BossHud _bossHud;
    
    [Signal] public delegate void ActorSpriteChangeEventHandler(Vector2 direction);
    
    public override void _Ready()
    {
        base._Ready();
        if (BossScript is null)
        {
            GD.PrintErr($"No boss script defined in {this.Name}");
            return;
        }

        _homePosition = this.GlobalPosition;

        CallDeferred(MethodName.InitDeferred);
    }

    private void InitDeferred()
    {
        _cameraMarker = new Marker2D();
        GameManager.Instance.CallDeferred("add_child", _cameraMarker);
        _cameraMarker.GlobalPosition = _homePosition + CameraOffset;

        if (BossScript.HudPrefab is not null)
        {
            _bossHud = BossScript.HudPrefab.Instantiate<BossHud>();
            GameManager.Instance.CallDeferred("add_child", _bossHud);

            _bossHud.Name = $"{BossName}_BossHud";
            _bossHud.Visible = false;
            _bossHud.BossName = BossName;
            _bossHud.BossMaxHealth = this.Health;
            _bossHud.BossHealth = this._currentHealth;
            _bossHud.SpellCardName = CurrentPhase.PhaseName;
            
            // TODO: Do some translation for health values to match the thresholds
            this.HealthChanged += (float newValue) => {_bossHud.BossHealth = newValue;};
            
            if (BossScript.PortraitTexture is not null)
            {
                // var canvas = new CanvasLayer();
                // canvas.Name = "BossPhaseAnimationCanvas";
           
                // _gameManager.CallDeferred("add_child", canvas);

                _animationTextureRect = new TextureRect();
                _animationTextureRect.Texture = BossScript.PortraitTexture;
  
                _bossHud.CallDeferred("add_child", _animationTextureRect);
            
                _animationTextureRect.Position = BossPhaseAnimationStartingPosition;

                _animationTextureRect.Visible = false;
            }
            
        }
    }
    

    public override void _Process(double delta)
    {
        base._Process(delta);

        if (!_started) return;
        if (_waiting) return;
        
        CurrentPhase.UpdatePhase(delta);
        if (_currentHealth <= CurrentPhase.Threshold && currentPhaseIndex + 1 < BossScript.Phases.Count)
        {
            currentPhaseIndex++;
            _bossHud.SpellCardName = CurrentPhase.PhaseName;
            StartPhase(CurrentPhase);
        }
    }

    protected override void ActivateDefeatScript()
    {
        GameManager.Instance.ClearBullets();
        base.ActivateDefeatScript();
    }

    protected override void Explode()
    {
        if (_bossHud is not null)
        {
            _bossHud.QueueFree();
        }
        
        GameManager.Instance.CameraTargetPlayer();
        
        base.Explode();
    }
    
    private void StartPhase(BossPhase phase)
    {
        GameManager.Instance.ClearBullets();
        if (phase.PlayAnimation)
        {
            _waiting = true;
            _invulnerable = true;
            _ = Switchphase(phase);
        }
        else
        {
            phase.Start(this);
        }
    }

    public void TakeDamage(int amount)
    {
        if (!_started) return;
        
        _currentHealth -= amount;
    }

    public bool Activate(ActivationType activationType = ActivationType.Toggle)
    {
        _started = true;
        if (_bossHud is not null)
        {
            _bossHud.Visible = true;
        }
        //GameManager.Instance.CameraTargetObject(_cameraMarker);
        StartPhase(CurrentPhase);

        return true;
    }

    private async Task Switchphase(BossPhase phase)
    {
        await PlayAnimation();
        
        _waiting = false;
        _invulnerable = false;
        phase.Start(this);
    }

    private async Task PlayAnimation()
    {
        _animationTextureRect.Modulate = new Color(_animationTextureRect.Modulate.R, _animationTextureRect.Modulate.G, _animationTextureRect.Modulate.B, 0f);
        _animationTextureRect.Position = BossPhaseAnimationStartingPosition;
        _animationTextureRect.Visible = true;
        
        var tween = GetTree().CreateTween();
        tween.SetEase(Tween.EaseType.InOut);
        tween.SetTrans(Tween.TransitionType.Linear);
        
        tween.TweenProperty(_animationTextureRect, "modulate:a", 1f, 0.2f);
        
        tween.TweenProperty(_animationTextureRect, "global_position", _animationTextureRect.GlobalPosition + new Vector2(-64f, 20f), 1.5f);
        
        tween.TweenProperty(_animationTextureRect, "modulate:a", 0f, 0.2f);
        
        //await Task.Delay(800);
        
        // Wait for the tween to finish
        await ToSignal(tween, "finished");
        
        _animationTextureRect.Visible = false;
    }

    public void ChangeSpriteDirection(Vector2 direction)
    {
        EmitSignal(SignalName.ActorSpriteChange, direction);
    }
}