using System;
using System.Collections.Generic;
using System.Linq;
using Cirno.Scripts.Actors;
using Cirno.Scripts.Components;
using Cirno.Scripts.Resources;
using Cirno.Scripts.Utils;
using Godot;
using Godot.Collections;
using Array = System.Array;

namespace Cirno.Scripts.AttackPatterns;

[GlobalClass]
[Tool]
public partial class SpiralPattern : AttackPattern
{
    [Export] public BulletResource BulletResource { get; set; }

    [Export] public Vector2 EmitterOffset { get; set; } = Vector2.Zero;
    
    //Export] public PackedScene BulletScene;
    //[Export] private float _bulletLifeTime = 20f;  // Switch to res
    //[Export] private bool _destroyOnCollision = false;  // Switch to res
    //[Export] private float bulletSpeed = 5f; // Switch to res
    [Export] public int bulletCount = 16;
    [Export] public float rotationSpeed = 0f;
    [Export] public float _rotationOffset = 0f;
    [Export] public float duration = 5f;
    [Export] public float spread = 360f;
    [Export] public float burstInterval = 0.5f;

    [ExportCategory("Burst")] [Export] public int ShotsPerBurst { get; private set; } = 100;

    [Export] public float BurstRate { get; private set; } = 0f;

    //[Export] private BulletOwner owner = BulletOwner.Enemy;  // Switch to res
    //[Export] private DamageType _damageType = DamageType.Neutral;  // Switch to res
    //[Export] private float _bulletDamage = 1f;  // Switch to res
    // [ExportGroup("Modifiers")] [Export] private BulletCreationModifier _modifier;
    // [ExportGroup("Modifiers")] [Export] private Array<TimeModifier> _timeModifiers;
    [ExportCategory("Other")] [Export] public bool _targetPlayer = false;
    [ExportCategory("Other")] [Export] public bool _predictPlayer = false;
    
    [ExportCategory("Overrides")]
    [Export] public bool OverrideOwner { get; private set; } = false;
    [Export] public BulletOwner Owner { get; private set; } = BulletOwner.None;
    [Export] public bool OverrideDamageType { get; private set; } = false;
    [Export] public DamageType DamageType { get; private set; } = DamageType.Neutral;
    [Export] public bool OverrideControllable { get; private set; } = false;
    [Export] public bool Controllable { get; private set; } = false;

    [ExportCategory("Extra Modifiers")]
    [Export]
    public bool OverrideCreationModifier { get; private set; } = false;

    [Export] public BulletCreationModifier Modifier;
    [Export] public Array<TimeModifier> TimeModifiers = [];
    
    protected virtual BulletInfo MakeBullet(Vector2 position, int count = 1, float spread = 0f, float rotationOffset = 0f)
    {
        var bullet = this.BulletResource.MakeBullet(position, count,
            spread, rotationOffset);

        if (OverrideOwner)
        {
            bullet.Owner = this.Owner;
        }

        if (OverrideDamageType)
        {
            bullet.DamageType = DamageType;
        }

        if (OverrideControllable)
        {
            bullet.Controllabe = Controllable;
        }

        if (OverrideCreationModifier)
        {
            bullet.Modifier = this.Modifier;
        }

        if (TimeModifiers.Count != 0)
        {
            bullet.TimeModifiers.AddRange(TimeModifiers);
        }
        
        //var bl = BulletResource.MakeBullet(position, bulletCount, angleOffset);
        //bl.Direction = direction;

        return bullet;

        // return new BulletInfo()
        // {
        //     Position = position,
        //     Direction = direction,
        //     LifeTime = _bulletLifeTime,
        //     DestroyOnCollision = _destroyOnCollision,
        //     Speed = bulletSpeed,
        //     Owner = owner,
        //     DamageType = _damageType,
        //     Damage = _bulletDamage,
        //     BulletCount = bulletCount,
        //     Spread = spread,
        //     BulletScene = BulletScene,
        //     RotationOffset = angleOffset,
        //     Modifier = _modifier,
        //     TimeModifiers = _timeModifiers.ToList()// _timeModifiers.Select(x => x.MakeClone()).ToList()
        //     // TimeModifiers = _timeModifiers?.Where(mod => mod != null).ToList() ?? new List<TimeModifier>()
        // };
    }

    public override IPatternMachine MakeMachine(Node parent)
    {
        return new SpiralPatternMachine(this, parent);
    }

    public class SpiralPatternMachine(SpiralPattern pattern, Node parent) : IPatternMachine
    {
        public Node Parent => parent;
        public IScriptHost ScriptHost { get; private set; }
        private double timer;
        private double burstTimer;
        //private double _burstRateTimer;
        private BulletSpawner spawner;

        private ShootStatus _state = ShootStatus.Idle;

        private int _burstBullets;
        
        public void Start()
        {
            ScriptHost = Parent as IScriptHost;
            
            timer = 0;
            _burstBullets = pattern.ShotsPerBurst;
            burstTimer = pattern.burstInterval; // start immediately
            //_burstRateTimer = pattern.burstInterval;
            spawner = parent.GetNode<BulletSpawner>("BulletSpawner");

            _state = ShootStatus.Shooting;
        }
        
        private void WaitingBurstUpdate(double delta)
        {
            timer += delta;
            burstTimer += delta;

            if (burstTimer >= pattern.burstInterval)
            {
                _state = ShootStatus.Shooting;
            }
        }

        private void WaitingReloadUpdate(double delta)
        {
            timer += delta;
            burstTimer += delta;
            
            if (burstTimer >= pattern.BurstRate)
            {
                _burstBullets = pattern.ShotsPerBurst;
                _state = ShootStatus.Shooting;
            }
        }

        private void ShootingUpdate(double delta)
        {
            timer += delta;
            burstTimer = 0;
            Shoot();
            _burstBullets--;

            if (_burstBullets <= 0)
            {
                _state = ShootStatus.WaitingReload;
            }
            else
            {
                _state = ShootStatus.WaitingBurst;
            }
        }

        public void UpdatePattern(double delta)
        {
            switch (_state)
            {
                case ShootStatus.Idle:
                case ShootStatus.Done:
                    return;
                case ShootStatus.Shooting:
                    ShootingUpdate(delta);
                    break;
                case ShootStatus.WaitingBurst:
                    WaitingBurstUpdate(delta);
                    break;
                case ShootStatus.WaitingReload:
                    WaitingReloadUpdate(delta);
                    break;
            }
            
            if (timer >= pattern.duration)
            {
                _state = ShootStatus.Done;
            }
            
           //  timer += delta;
           //  burstTimer += delta;
           //  //_burstRateTimer += delta;
           //
           //  if (timer > pattern.duration)
           //  {
           //      return;
           //  }
           //
           //  if (burstTimer < pattern.burstInterval) return;
           //
           // Shoot();
           //
           //
           //
           //  burstTimer = 0;
        }

        private void Shoot()
        {
            float angleOffset = pattern._rotationOffset + (float)(pattern.rotationSpeed * timer);

            Vector2 direction = pattern.BulletResource.Direction;

            if (pattern._targetPlayer && GameManager.Instance.PlayerPosition.HasValue)
            {
                if (pattern._predictPlayer && GameManager.Instance.PlayerVelocity.HasValue)
                {
                    var predictedDirection = MathFunctions.PredictInterceptPosition(ScriptHost.ParentObject.GlobalPosition,
                        GameManager.Instance.PlayerPosition.Value, GameManager.Instance.PlayerVelocity.Value,
                        pattern.BulletResource.BulletSpeed);
                    if (predictedDirection.HasValue)
                    {
                        direction = (predictedDirection.Value - ScriptHost.ParentObject.GlobalPosition).Normalized();
                    }
                }
                else
                {
                    direction = (GameManager.Instance.PlayerPosition.Value - ScriptHost.ParentObject.GlobalPosition).Normalized();
                }
            }

            var bullet = pattern.MakeBullet(ScriptHost.ParentObject.GlobalPosition + pattern.EmitterOffset, pattern.bulletCount,
                pattern.spread, angleOffset);
            
            bullet.Direction = direction;

            //spawner.SpawnBullet(MakeBullet(Boss.GlobalPosition, direction, angleOffset));
            spawner.SpawnBullet(bullet);
        }


        public bool IsComplete()
        {
            //return timer >= pattern.duration;
            return _state is ShootStatus.Done;
        }

        private enum ShootStatus
        {
            Idle,
            Shooting,
            WaitingBurst,
            WaitingReload,
            Done
        }
    }
}