using System;
using System.Collections.Generic;
using FlappyBird.Core;
using UnityEngine;
using Zenject;

namespace FlappyBird.Pipes
{
    public class PipeSpawner : IInitializable, ITickable, IDisposable
    {
        private readonly IObjectPoolManager _objectPoolManager;
        private readonly IGameManager _gameManager;
        private readonly PipeSettings _settings;
        private readonly GameObject _pipePrefab;

        private readonly List<PipeView> _activePipes = new List<PipeView>();

        private bool _isRunning;
        private float _spawnTimer;

        [Inject]
        public PipeSpawner(
            IObjectPoolManager objectPoolManager,
            IGameManager gameManager,
            PipeSettings settings,
            [Inject(Id = "PipePrefab")] GameObject pipePrefab)
        {
            _objectPoolManager = objectPoolManager;
            _gameManager = gameManager;
            _settings = settings;
            _pipePrefab = pipePrefab;
        }

        /// <summary>
        /// Initializes the spawner by registering the Pipe pool, subscribing to game state changes,
        /// and setting the initial spawn timer based on settings.
        /// </summary>
        public void Initialize()
        {
            // Register the pool with the new generic ObjectPoolManager
            _objectPoolManager.RegisterPool<PipeView>(_pipePrefab, _settings.initialPoolSize);

            _gameManager.OnGameStateChanged += HandleGameStateChanged;
            ApplyState(_gameManager.CurrentState);
        }

        public void Dispose()
        {
            _gameManager.OnGameStateChanged -= HandleGameStateChanged;
        }

        public void Tick()
        {
            if (!_isRunning)
            {
                return;
            }

            MoveActivePipes();
            UpdateSpawnTimer();
        }

        private void HandleGameStateChanged(GameState state)
        {
            ApplyState(state);
        }

        private void ApplyState(GameState state)
        {
            if (state == GameState.Playing)
            {
                _isRunning = true;
                _spawnTimer = _settings.spawnImmediately ? 0f : _settings.spawnInterval;
                return;
            }

            _isRunning = false;

            if (state == GameState.Menu)
            {
                DespawnAllActivePipes();
            }
        }

        private void UpdateSpawnTimer()
        {
            _spawnTimer -= Time.deltaTime;
            if (_spawnTimer > 0f)
            {
                return;
            }

            SpawnPipe();
            _spawnTimer += Mathf.Max(0.01f, _settings.spawnInterval);
        }

        private void SpawnPipe()
        {
            PipeView pipeView = _objectPoolManager.Get<PipeView>();

            // Randomize the vertical position of the gap
            float gapCenterY = UnityEngine.Random.Range(_settings.minGapCenterY, _settings.maxGapCenterY);

            pipeView.ConfigureGap(gapCenterY, _settings.gapSize, _settings.scoreTriggerWidth);
            pipeView.SetWorldPosition(new Vector3(_settings.spawnX, 0f, 0f));

            _activePipes.Add(pipeView);
        }

        private void MoveActivePipes()
        {
            float step = _settings.moveSpeed * Time.deltaTime;

            for (int i = _activePipes.Count - 1; i >= 0; i--)
            {
                PipeView pipeView = _activePipes[i];
                pipeView.MoveLeft(step);

                // Despawn if the pipe has moved past the despawn threshold
                if (pipeView.XPosition > _settings.despawnX)
                {
                    continue;
                }

                _activePipes.RemoveAt(i);
                _objectPoolManager.Return(pipeView);
            }
        }

        private void DespawnAllActivePipes()
        {
            for (int i = _activePipes.Count - 1; i >= 0; i--)
            {
                _objectPoolManager.Return(_activePipes[i]);
            }

            _activePipes.Clear();
        }
    }
}