using System;
using System.Collections.Generic;
using Core.Ports;
using UnityEngine;
using Random = System.Random;

namespace Core.Domain
{
    public class GameSession
    {
        private const string HighScoreKey = "HighScore";
        private const float PowerUpSpawnInterval = 25f;

        public int Score { get; private set; }
        public int HighScore { get; private set; }
        public bool IsGameOver { get; private set; }

        public float TimeDilation { get; private set; } = 1.0f;
        public float NpcSpawnTime { get; private set; } = 30f;

        public event Action<int> OnScoreChanged;
        public event Action<string> OnOrbSpawned;
        public event Action OnOrbReset;
        public event Action OnGameOver;
        public event Action OnSpawnNpc;
        public event Action<PowerUpType, string> OnSpawnPowerUp;

        private readonly List<Tile> _tiles;
        private readonly IPersistenceService _persistenceService;
        private readonly Random _rng = new();
        private int _playerFloorIndex = 0;
        private float _timeSinceStart;
        private float _npcTimer;
        private float _powerUpTimer;

        private float _timeSlowTimer;

        // Combo System
        private float _lastOrbTime;
        public int ComboMultiplier { get; private set; } = 1;
        public event Action<int> OnComboUpdated;

        public GameSession(List<Tile> tiles, IPersistenceService persistenceService)
        {
            _tiles = tiles;
            _persistenceService = persistenceService;

            Score = 0;
            IsGameOver = false;

            HighScore = _persistenceService.Load(HighScoreKey, 0);
        }

        public void StartGame()
        {
            _timeSinceStart = 0f;
            _powerUpTimer = 0f;
            TimeDilation = 1.0f;

            ComboMultiplier = 1;
            _lastOrbTime = -999f;

            SpawnNextOrb();
        }

        public void Tick(float deltaTime)
        {
            if (IsGameOver) return;

            _timeSinceStart += deltaTime;
            _npcTimer += deltaTime;
            
            if (_npcTimer >= NpcSpawnTime)
            {
                _npcTimer = 0f;
                OnSpawnNpc?.Invoke();
                NpcSpawnTime = Mathf.Max(5f, NpcSpawnTime * 0.95f);
            }

            _powerUpTimer += deltaTime;
            if (_powerUpTimer >= PowerUpSpawnInterval)
            {
                _powerUpTimer = 0f;
                SpawnRandomPowerUp();
            }

            if (_timeSlowTimer > 0)
            {
                _timeSlowTimer -= deltaTime;
                if (_timeSlowTimer <= 0)
                {
                    TimeDilation = 1.0f;
                }
            }
        }

        public void ActivateTimeSlow(float duration)
        {
            _timeSlowTimer = duration;
            TimeDilation = 0.3f; // Slow down to 30%
        }

        public void OrbCollected()
        {
            if (IsGameOver) return;

            // Combo Check (2 second window)
            if (_timeSinceStart - _lastOrbTime < 2.0f)
            {
                ComboMultiplier++;
            }
            else
            {
                ComboMultiplier = 1;
            }
            _lastOrbTime = _timeSinceStart;

            OnComboUpdated?.Invoke(ComboMultiplier);

            Score += 10 * ComboMultiplier;
            OnScoreChanged?.Invoke(Score);
            SpawnNextOrb();
        }

        private void SpawnNextOrb()
        {
            var validTiles = _tiles.FindAll(t =>
                t.CurrentState == TileState.Stable &&
                t.Floor == _playerFloorIndex
            );

            if (validTiles.Count == 0)
            {
                validTiles = _tiles.FindAll(t => t.CurrentState == TileState.Stable);
            }

            if (validTiles.Count == 0)
            {
                EndGame();
                return;
            }

            var pick = validTiles[_rng.Next(validTiles.Count)];
            OnOrbSpawned?.Invoke(pick.Id);
        }

        public void EndGame()
        {
            if (IsGameOver) return;

            IsGameOver = true;

            if (Score > HighScore)
            {
                HighScore = Score;
                _persistenceService.Save(HighScoreKey, HighScore);
            }

            OnGameOver?.Invoke();
        }

        public void SetPlayerFloor(int floorIndex)
        {
            if (_playerFloorIndex == floorIndex) return;

            _playerFloorIndex = floorIndex;

            if (IsGameOver) return;

            OnOrbReset?.Invoke();
            SpawnNextOrb();
        }

        private void SpawnRandomPowerUp()
        {
            var validTiles = _tiles.FindAll(t => 
                t.CurrentState == TileState.Stable && 
                t.Floor == _playerFloorIndex
            );

            if (validTiles.Count == 0)
            {
                validTiles = _tiles.FindAll(t => t.CurrentState == TileState.Stable);
            }

            if (validTiles.Count == 0) return;

            var tile = validTiles[_rng.Next(validTiles.Count)];

            var rand = _rng.Next(0, 4);
            var type = PowerUpType.LightFooted;
            switch (rand)
            {
                case 0: type = PowerUpType.LightFooted; break;
                case 1: type = PowerUpType.SpeedBoost; break;
                case 3: type = PowerUpType.TimeSlow; break;
            }

            OnSpawnPowerUp?.Invoke(type, tile.Id);
        }
    }
}