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

namespace FlappyBird.Environment
{
    public class GroundSpawner : IInitializable, ITickable, IDisposable
    {
        private readonly IObjectPoolManager _objectPoolManager;
        private readonly IGameManager _gameManager;
        private readonly PipeSettings _pipeSettings;
        private readonly GroundSettings _groundSettings;
        private readonly GameObject _groundPrefab;

        private readonly List<GroundView> _activeGrounds = new List<GroundView>();

        private bool _isRunning;

        [Inject]
        public GroundSpawner(
            IObjectPoolManager objectPoolManager,
            IGameManager gameManager,
            PipeSettings pipeSettings,
            GroundSettings groundSettings,
            [Inject(Id = "GroundPrefab")] GameObject groundPrefab)
        {
            _objectPoolManager = objectPoolManager;
            _gameManager = gameManager;
            _pipeSettings = pipeSettings;
            _groundSettings = groundSettings;
            _groundPrefab = groundPrefab;
        }

        /// <summary>
        /// Initializes the ground system by registering the object pool and 
        /// spawning initial segments. They will remain stationary until the game starts.
        /// </summary>
        public void Initialize()
        {
            _objectPoolManager.RegisterPool<GroundView>(_groundPrefab, _groundSettings.initialPoolSize);

            _gameManager.OnGameStateChanged += HandleGameStateChanged;

            // Pre-spawn segments so the floor is visible in the Menu state
            float currentX = _groundSettings.spawnX;
            for (int i = 0; i < Mathf.Max(1, _groundSettings.initialPoolSize); i++)
            {
                SpawnGround(currentX);
                currentX += _groundSettings.groundWidth;
            }

            // Sets initial movement state based on current GameManager state (Menu = stopped)
            ApplyState(_gameManager.CurrentState);
        }

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

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

            MoveActiveGrounds();
        }

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

        private void ApplyState(GameState state)
        {
            // Ground only moves during active gameplay
            _isRunning = state == GameState.Playing;
        }

        private void MoveActiveGrounds()
        {
            float step = _pipeSettings.moveSpeed * Time.deltaTime;
            float rightmostX = GetRightmostGroundX();

            for (int i = _activeGrounds.Count - 1; i >= 0; i--)
            {
                GroundView groundView = _activeGrounds[i];
                groundView.MoveLeft(step);

                if (groundView.XPosition > _groundSettings.despawnX)
                {
                    continue;
                }

                _activeGrounds.RemoveAt(i);
                _objectPoolManager.Return(groundView);

                // Re-spawn at the end of the chain
                SpawnGround(rightmostX + _groundSettings.groundWidth - step);
                rightmostX += _groundSettings.groundWidth;
            }
        }

        private float GetRightmostGroundX()
        {
            float maxX = float.MinValue;
            foreach (var ground in _activeGrounds)
            {
                if (ground.XPosition > maxX) maxX = ground.XPosition;
            }
            return maxX == float.MinValue ? _groundSettings.spawnX : maxX;
        }

        private void SpawnGround(float xPosition)
        {
            GroundView groundView = _objectPoolManager.Get<GroundView>();
            groundView.SetPosition(new Vector3(xPosition, _groundSettings.yPosition, 0f));
            _activeGrounds.Add(groundView);
        }
    }
}