using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils;
using CustomRounds.Attributes;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;

namespace CustomRounds.Rounds;

public class SavedValue<T>(T value)
{
    public T Value { get; set; } = value;
    private readonly T _savedValue = value;

    public void Reset()
    {
        Value = _savedValue;
    }

    public override string ToString()
    {
        return $"Value: {Value}, SavedValue: {_savedValue}";
    }
}

[CustomRound(Name = nameof(ChickenRound))]
public class ChickenRound(Plugin plugin) : ICustomRound
{
    private const int MaxChickens = 5;
    private const string MagicZoneModel = "models/props/de_mirage/roof_plank_a.vmdl";

    private readonly List<CChicken> _chickens = [];
    private readonly List<CParticleSystem> _particles = [];

    private readonly MemoryFunctionVoid<CBaseEntity, CBaseEntity, IntPtr, IntPtr> _setParent =
        new("48 85 F6 74 ? 48 8B 47 10 F6 40 31 02 75 ? 48 8B 46 10 F6 40 31 02 75 ? B8 ? ? ? ?");

    // 421, 2688, 256 | 11, -7, 0
    // 402, 2850, 256 | 13, 75, 0
    // 250, 2852, 256 | 17, 130, 0
    // 270, 2691, 256 | 20, -134, 0

    private readonly Vector[] _positions =
    [
        new Vector(-467.8291f, -1556.3018f, -39.96875f),
        new Vector(48.475086f, -1678.1808f, -167.96875f),
        new Vector(138.41733f, -1429.3252f, -175.96875f),
        new Vector(139.6984f, -1996.8335f, -167.96875f),
        new Vector(78.7923f, -2167.9688f, -39.96875f),
        new Vector(-787.3938f, -2507.288f, -167.96875f),
        new Vector(-803.7273f, -1891.9352f, -179.96875f),
        new Vector(-745.54913f, -1534.501f, -167.96875f),
        new Vector(-287.9016f, -1715.9772f, -167.96875f)
    ];

    // private readonly Vector[] _spawnPoints =
    // [
    //     new Vector(421, 2688, 256),
    //     new Vector(402, 2850, 256),
    //     new Vector(250, 2852, 256),
    //     new Vector(270, 2691, 256)
    // ];


    private readonly SavedValue<float> _spawnRate = new(2);
    private readonly SavedValue<float> _spawnInterval = new(5);
    private readonly SavedValue<int> _countdown = new(5);
    private readonly SavedValue<int> _currentChicken = new(0);

    private CDynamicProp? _targetEntity;
    private Timer? _spawnTimer;
    private Timer? _countdownTimer;
    private readonly List<Timer?> _gayTimer = [];

    private Dictionary<CChicken, bool> _chickenPosition = new();

    private WinLinux<int> _offset = new(179, 178);

    private readonly Dictionary<CChicken, DateTime> _chickenLastJumpTime = new();

    public void Start()
    {
        Reset();
        RemoveChickens();
        VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre);

        var players = Utilities.GetPlayers();

        // foreach (var (player, spawnPoint) in players.Zip(_spawnPoints, (p, s) => (p, s)))
        // {
        //     var playerPawn = player.PlayerPawn.Value;
        //     if (playerPawn is null) continue;
        //
        //     playerPawn.Teleport(spawnPoint);
        // }

        plugin.RegisterEvent<EventRoundFreezeEnd>(EventRoundFreezeEnd);
    }

    private HookResult EventRoundFreezeEnd(EventRoundFreezeEnd @event, GameEventInfo info)
    {
        _countdownTimer = plugin.AddTimer(1, () =>
        {
            if (_countdown.Value <= 5)
            {
                foreach (var player in Utilities.GetPlayers())
                {
                    player.PrintToChat($"{_countdown}");
                }
            }

            if (_countdown.Value <= 0)
            {
                foreach (var player in Utilities.GetPlayers().Where(u => u.IsValid && u.PawnIsAlive))
                {
                    player.RemoveWeapons();

                    player.GiveNamedItem(CsItem.Knife);
                    player.GiveNamedItem(CsItem.AK47);
                }

                var targetEntity = Utilities.CreateEntityByName<CDynamicProp>("prop_dynamic");
                if (targetEntity is not null)
                {
                    targetEntity.TakesDamage = false;
                    targetEntity.DispatchSpawn();
                    targetEntity.Teleport(new Vector(-469.2815f, -2187.0203f, -179.57928f));
                    targetEntity.RenderMode = RenderMode_t.kRenderNone;
                }

                _targetEntity = targetEntity;

                Server.PrintToChatAll($"[{ChatColors.Blue}CustomRounds\x01] CHICKEN ROUND");

                _spawnTimer = plugin.AddTimer(_spawnInterval.Value, Callback);
                _countdownTimer?.Kill();
            }

            _countdown.Value--;
        }, TimerFlags.REPEAT | TimerFlags.STOP_ON_MAPCHANGE);
        return HookResult.Continue;
    }

    private void RemoveChickens()
    {
        foreach (var entityInstance in Utilities.GetAllEntities()
                     .Where(e => e.DesignerName.Contains("chicken") && e.IsValid))
        {
            entityInstance.Remove();
        }
    }

    private HookResult OnTakeDamage(DynamicHook hook)
    {
        var entityInstance = hook.GetParam<CEntityInstance>(0);
        var info = hook.GetParam<CTakeDamageInfo>(1);

        var attacker = info.Attacker.Value;

        var isInstanceChicken = entityInstance.DesignerName.Contains("chicken");
        var isAttackerPlayer = attacker?.DesignerName.Contains("player");
        var isAttackerChicken = attacker?.DesignerName.Contains("chicken");

        if (isInstanceChicken && isAttackerPlayer == true)
        {
            var cChicken = entityInstance.As<CChicken>();
            CreateParticle(cChicken);
            Explode(cChicken);
            ChangeChickenLeader(cChicken, _targetEntity?.EntityHandle.Raw ?? 1302);

            return HookResult.Continue;
        }

        if (isInstanceChicken && attacker?.DesignerName.Contains("env_explosion") == true ||
            isInstanceChicken && isAttackerChicken == true)
        {
            info.Damage = 0;
            return HookResult.Changed;
        }

        return HookResult.Continue;
    }

    private void CreateParticle(CBaseEntity chicken)
    {
        if (!chicken.IsValid) return;
        var particle = Utilities.CreateEntityByName<CParticleSystem>("info_particle_system");
        if (particle is null) return;

        particle.EffectName = Plugin.ExplosionHeGrenade;
        particle.DispatchSpawn();
        particle.Teleport(chicken.AbsOrigin);

        Server.NextFrame(() => particle.AcceptInput("Start"));

        _particles.Add(particle);
    }

    private void Callback()
    {
        if (_currentChicken.Value >= MaxChickens)
            return;

        VirtualFunctions.ClientPrintAll(HudDestination.Alert, $"Kуриц осталось: {MaxChickens - _currentChicken.Value}",
            0, 0,
            0, 0);

        _spawnInterval.Value *= 0.9f;
        if (_spawnInterval.Value < 1)
            _spawnInterval.Value = 1;

        _spawnRate.Value += 0.1f;

        for (int i = 0; i < _spawnRate.Value; i++)
        {
            CreateChicken();
        }

        _spawnTimer = plugin.AddTimer(_spawnInterval.Value, Callback);
    }

    private void CreateChicken()
    {
        var chicken = Utilities.CreateEntityByName<CChicken>("chicken");
        if (chicken is null) return;

        var raw = _targetEntity?.EntityHandle.Raw;
        if (raw is null) return;

        // chicken.ExplodeDamage = 70;
        // chicken.ExplodeRadius = 40;

        ChangeChickenLeader(chicken, raw.Value);
        chicken.DispatchSpawn();
        ChangeChickenLeader(chicken, raw.Value);
        Server.NextFrame(() => OnChickenSpawn(chicken));

        var position = _positions[Random.Shared.Next(_positions.Length)];

        position.X += Random.Shared.NextSingle() * 20 - 10;
        position.Y += Random.Shared.NextSingle() * 20 - 10;

        chicken.Teleport(position);

        var timer = plugin.AddTimer(0.5f, () => TimerChickenCallback(chicken),
            TimerFlags.REPEAT | TimerFlags.STOP_ON_MAPCHANGE);

        _gayTimer.Add(timer);

        _currentChicken.Value++;
        _chickens.Add(chicken);
        _chickenLastJumpTime[chicken] = DateTime.UtcNow;
    }

    private void TimerChickenCallback(CChicken chicken)
    {
        if (!chicken.IsValid || _targetEntity?.IsValid == false) return;

        var players = Utilities.GetPlayers().Where(u => u is { PawnIsAlive: true, IsValid: true });

        var nearestPlayer = players
            .Select(u => new
            {
                Player = u,
                Distance = Vector3.Distance(chicken.AbsOrigin!.ToVector3(),
                    u.PlayerPawn.Value.AbsOrigin!.ToVector3())
            })
            .OrderBy(u => u.Distance)
            .FirstOrDefault();

        if (nearestPlayer != null)
        {
            if (nearestPlayer.Distance < 70)
            {
                Explode(chicken);
            }
            else if (nearestPlayer.Distance < 170)
            {
                JumpAtPlayer(chicken, nearestPlayer.Player);
            }
            else if (nearestPlayer.Distance < 300)
            {
                ChangeChickenLeader(chicken, nearestPlayer.Player.PlayerPawn.Raw);
            }
        }
    }

    private void ChangeChickenLeader(CChicken chicken, uint raw)
    {
        chicken.Leader.Raw = raw;
        Utilities.SetStateChanged(chicken, "CChicken", "m_leader");
    }

    private void OnChickenSpawn(CChicken chicken)
    {
        //chicken.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
        //chicken.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_NONE;
        //
        //var collisionRulesChanged = new VirtualFunctionVoid<nint>(chicken.Handle, _offset.Get());
        //collisionRulesChanged.Invoke(chicken.Handle);
    }

    private void JumpAtPlayer(CChicken chicken, CCSPlayerController player)
    {
        if (_chickenLastJumpTime.TryGetValue(chicken, out var time) &&
            DateTime.UtcNow - time < TimeSpan.FromSeconds(2))
            return;

        _chickenLastJumpTime[chicken] = DateTime.UtcNow;

        var direction =
            Vector3.Normalize(player.PlayerPawn.Value!.AbsOrigin!.ToVector3() - chicken.AbsOrigin!.ToVector3());

        const float jumpSpeed = 150.0f;

        var jumpVelocity = new Vector(direction.X * jumpSpeed, direction.Y * jumpSpeed, 300.0f);

        jumpVelocity.X += Random.Shared.NextSingle() * 20 - 10;
        jumpVelocity.Y += Random.Shared.NextSingle() * 20 - 10;

        chicken.Teleport(new Vector(chicken.AbsOrigin.X, chicken.AbsOrigin.Y, chicken.AbsOrigin.Z + 20),
            velocity: jumpVelocity);
    }

    private void Explode(CBaseEntity entity)
    {
        var explosion = Utilities.CreateEntityByName<CEnvExplosion>("env_explosion");
        if (explosion is null || !explosion.IsValid)
            return;

        explosion.RadiusOverride = 150;
        explosion.Magnitude = 50;
        explosion.PlayerDamage = 25;
        explosion.DamageForce = 25;
        explosion.DispatchSpawn();

        explosion.Teleport(entity.AbsOrigin);
        Server.NextFrame(() => { explosion.AcceptInput("Explode"); });

        CreateParticle(entity);
        entity.Remove();
    }

    private void Reset()
    {
        _currentChicken.Reset();
        _spawnInterval.Reset();
        _spawnRate.Reset();
        _countdown.Reset();

        _countdownTimer?.Kill();
        _countdownTimer = null;

        _spawnTimer?.Kill();
        _spawnTimer = null;

        foreach (var timer in _gayTimer)
        {
            timer?.Kill();
        }

        if (_targetEntity?.IsValid == true)
        {
            _targetEntity.Remove();
        }

        foreach (var chicken in _chickens.Where(cChicken => cChicken.IsValid))
        {
            chicken.Remove();
        }

        foreach (var particleSystem in _particles.Where(p => p.IsValid))
        {
            particleSystem.Remove();
        }
    }

    public void End()
    {
        Reset();
        VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage, HookMode.Pre);
    }
}

public static class VectorUtils
{
    public static Vector ToVector(this Vector3 v)
    {
        return new Vector(v.X, v.Y, 0);
    }

    public static Vector3 ToVector3(this Vector v)
    {
        return new Vector3(v.X, v.Y, 0);
    }
}

на протяжении этих 3х минут каждые 20 секунд количество разом спавнящихся куриц увеличивается, появляются волнами, можно добавить плашку отсчета волн
1. 20 сек - 25 кур
2. 40 сек - 50 кур
3. 60 сек - 75 кур
4. 80 сек - 100 кур
5. 100 сек - 125 кур
6. 120 сек - 150 кур
7. 140 сек - 175 кур
8. 160 сек  - 200 кур
9. 180 сек - 225 кур

нужно ерализовал волн по спавнам куриц.