using UnityEngine;
using Zenject;
using FlappyBird.Core;
using FlappyBird.Gameplay;
using FlappyBird.Gameplay.Bird;
using FlappyBird.Gameplay.Pipes;

namespace FlappyBird.Installers
{
    /// <summary>
    /// Zenject MonoInstaller for core gameplay bindings.
    /// Attach this to the SceneContext GameObject in each gameplay scene.
    /// </summary>
    public sealed class GameInstaller : MonoInstaller
    {
        [Header("Game Management")]
        [Tooltip("GameManagerView MonoBehaviour in the scene.")]
        [SerializeField] private GameManagerView _gameManagerView;

        [Tooltip("BirdCollisionView MonoBehaviour on the bird GameObject.")]
        [SerializeField] private BirdCollisionView _birdCollisionView;

        [Header("Bird")]
        [Tooltip("Drag the Bird GameObject here (must have Rigidbody2D).")]
        [SerializeField] private BirdView _birdView;

        [Tooltip("BirdSettings ScriptableObject asset.")]
        [SerializeField] private BirdSettings _birdSettings;

        [Header("Pipes")]
        [Tooltip("PipeSettings ScriptableObject asset.")]
        [SerializeField] private PipeSettings _pipeSettings;

        [Tooltip("Pipe-pair prefab with a PipeView component.")]
        [SerializeField] private PipeView _pipePrefab;

        [Tooltip("PipeSpawnerTicker MonoBehaviour in the scene.")]
        [SerializeField] private PipeSpawnerTicker _pipeSpawnerTicker;

        public override void InstallBindings()
        {
            BindGameState();
            BindScore();
            BindBird();
            BindPipes();
            BindDeath();
        }

        // ── Game State ─────────────────────────────────────────────────────

        private void BindGameState()
        {
            Container.Bind<IGameStateManager>()
                     .To<GameStateManager>()
                     .AsSingle();

            // Bind the concrete MonoBehaviour so BirdCollisionView can resolve it by type.
            Container.Bind<GameManagerView>()
                     .FromInstance(_gameManagerView)
                     .AsSingle();

            Container.QueueForInject(_gameManagerView);
            Container.QueueForInject(_birdCollisionView);
        }

        // ── Score ──────────────────────────────────────────────────────────

        private void BindScore()
        {
            Container.Bind<IScoreManager>()
                     .To<ScoreManager>()
                     .AsSingle();
        }

        // ── Bird ───────────────────────────────────────────────────────────

        private void BindBird()
        {
            Container.Bind<Rigidbody2D>()
                     .FromComponentOn(_birdView.gameObject)
                     .AsSingle();

            Container.BindInstance(_birdSettings).AsSingle();

            Container.Bind<IBirdController>()
                     .To<BirdController>()
                     .AsSingle();

            Container.QueueForInject(_birdView);
        }

        // ── Pipes ──────────────────────────────────────────────────────────

        private void BindPipes()
        {
            Container.BindInstance(_pipeSettings).AsSingle();

            Container.BindFactory<PipeView, PipeView.Factory>()
                     .FromComponentInNewPrefab(_pipePrefab)
                     .AsSingle();

            Container.BindInterfacesTo<PipePool>()
                     .AsSingle();

            Container.Bind<IPipeSpawner>()
                     .To<PipeSpawner>()
                     .AsSingle();

            Container.QueueForInject(_pipeSpawnerTicker);
        }

        // ── Death ──────────────────────────────────────────────────────────

        private void BindDeath()
        {
            // BindInterfacesTo registers the same instance for both
            // IDeathHandler and IInitializable (so Zenject calls Initialize()).
            Container.BindInterfacesTo<DeathHandler>()
                     .AsSingle();
        }
    }
}