using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GameManager : MonoBehaviour
{
    public enum GameState { Menu, Playing, GameOver }

    public static GameManager Instance;

    public PlayerController playerController;
    public Text scoreText;
    public Text livesText;
    public Text waveText;
    public Text comboText;
    public Text highScoreText;
    public Text statusText;
    public GameObject startPanel;
    public GameObject gameOverPanel;
    public int score;
    public int lives = 3;
    public GameObject enemyPrefab;
    public int rows = 4;
    public int columns = 5;
    public float spacingX = 1.35f;
    public float spacingY = 1.0f;

    public GameState CurrentState { get; private set; }

    private List<GameObject> enemies = new List<GameObject>();
    private int waveNumber = 1;
    private bool firstWave = true;
    private int combo = 1;
    private float lastKillTime = -999f;
    private int highScore;
    private const float ComboWindowSeconds = 1.25f;
    private GameObject bossShipPrefab;
    private GameObject activeBoss;
    private float bossSpawnTimer = 0f;
    private const float BossSpawnInterval = 12f;

    private void Awake()
    {
        Instance = this;
        CurrentState = GameState.Menu;
        CreateEnemyTemplate();
        CreateBossShipTemplate();
        LoadHighScore();
    }

    private void Start()
    {
        UpdateHud();
        ShowMenu();
    }

    private void Update()
    {
        if (CurrentState != GameState.Playing) return;

        bossSpawnTimer += Time.deltaTime;
        if (bossSpawnTimer >= BossSpawnInterval && (activeBoss == null || !activeBoss.activeInHierarchy))
        {
            SpawnBossShip();
            bossSpawnTimer = 0f;
        }
    }

    public void AddScore(int points)
    {
        score += points;
        if (score > highScore)
        {
            highScore = score;
            SaveHighScore();
        }
        UpdateHud();
    }

    public void RegisterPlayer(PlayerController player)
    {
        playerController = player;
    }

    public void StartNewGame()
    {
        score = 0;
        lives = 3;
        waveNumber = 1;
        firstWave = true;
        combo = 1;
        lastKillTime = -999f;
        bossSpawnTimer = 0f;
        CurrentState = GameState.Playing;
        HidePanels();
        UpdateHud();
        if (playerController != null) playerController.ResetPlayer();
        SpawnWave();
    }

    public void NotifyEnemyDestroyed(GameObject enemyObject)
    {
        if (CurrentState != GameState.Playing) return;

        UpdateCombo();
        int points = 100 + waveNumber * 10 + combo * 20;
        score += points;
        if (score > highScore)
        {
            highScore = score;
            SaveHighScore();
        }

        enemies.Remove(enemyObject);
        if (AudioManager.Instance != null)
            AudioManager.Instance.PlayExplosion(enemyObject.transform.position);
        ExplosionEffect.Spawn(enemyObject.transform.position);
        UpdateHud();

        if (enemies.Count == 0)
            SpawnWave();
    }

    public void PlayerHit()
    {
        if (CurrentState != GameState.Playing) return;

        lives--;
        combo = 1;
        lastKillTime = -999f;
        if (AudioManager.Instance != null) AudioManager.Instance.PlayHit();
        UpdateHud();

        if (lives <= 0)
            EndGame();
        else if (playerController != null)
            playerController.ResetPlayer();
    }

    private void EndGame()
    {
        CurrentState = GameState.GameOver;
        if (AudioManager.Instance != null) AudioManager.Instance.PlayGameOver();
        ClearEnemies();
        ShowGameOver();
    }

    public void SpawnWave()
    {
        if (CurrentState != GameState.Playing) return;

        if (!firstWave)
            waveNumber++;
        else
            firstWave = false;

        ClearEnemies();

        int effectiveRows = Mathf.Min(rows + (waveNumber - 1) / 2, 6);
        int effectiveColumns = Mathf.Min(columns + (waveNumber - 1) / 3, 8);
        float currentSpacingX = Mathf.Max(1.0f, spacingX - (waveNumber - 1) * 0.04f);
        float currentSpacingY = spacingY + Mathf.Min(0.2f, (waveNumber - 1) * 0.02f);

        for (int row = 0; row < effectiveRows; row++)
        {
            for (int col = 0; col < effectiveColumns; col++)
            {
                float xPos = col * currentSpacingX - ((effectiveColumns - 1) * currentSpacingX) / 2f;
                float yPos = 3.6f - row * currentSpacingY;
                var enemyObject = Instantiate(enemyPrefab, new Vector3(xPos, yPos, 0f), Quaternion.identity);
                enemyObject.SetActive(true);
                enemyObject.name = "Enemy_" + row + "_" + col;
                enemyObject.tag = "Enemy";

                var rend = enemyObject.GetComponent<SpriteRenderer>();
                rend.sprite = CreateFaceSprite();
                rend.color = Color.white;
                rend.sortingOrder = 1;

                var col2d = enemyObject.GetComponent<BoxCollider2D>();
                col2d.isTrigger = true;
                col2d.size = new Vector2(0.9f, 0.9f);

                var rb = enemyObject.GetComponent<Rigidbody2D>();
                rb.gravityScale = 0f;
                rb.bodyType = RigidbodyType2D.Kinematic;
                rb.simulated = true;

                var enemy = enemyObject.GetComponent<Enemy>();
                enemy.speed = 1.4f + row * 0.06f + (waveNumber - 1) * 0.07f;

                enemies.Add(enemyObject);
            }
        }
        UpdateHud();
    }

    private void UpdateCombo()
    {
        if (Time.time - lastKillTime <= ComboWindowSeconds)
            combo++;
        else
            combo = 1;
        lastKillTime = Time.time;
    }

    private void LoadHighScore()
    {
        highScore = PlayerPrefs.GetInt("FaceInvaders.HighScore", 0);
    }

    private void SaveHighScore()
    {
        PlayerPrefs.SetInt("FaceInvaders.HighScore", highScore);
        PlayerPrefs.Save();
    }

    private void CreateEnemyTemplate()
    {
        enemyPrefab = new GameObject("EnemyTemplate");
        enemyPrefab.AddComponent<SpriteRenderer>();
        enemyPrefab.AddComponent<BoxCollider2D>();
        enemyPrefab.AddComponent<Rigidbody2D>();
        enemyPrefab.AddComponent<Enemy>();
        enemyPrefab.SetActive(false);
    }

    private void CreateBossShipTemplate()
    {
        bossShipPrefab = new GameObject("BossShipTemplate");
        bossShipPrefab.AddComponent<SpriteRenderer>();
        bossShipPrefab.AddComponent<BoxCollider2D>();
        bossShipPrefab.AddComponent<Rigidbody2D>();
        bossShipPrefab.AddComponent<BossShip>();
        bossShipPrefab.SetActive(false);
    }

    private void SpawnBossShip()
    {
        if (activeBoss != null && activeBoss.activeInHierarchy) return;

        activeBoss = Instantiate(bossShipPrefab, new Vector3(0f, 6f, 0f), Quaternion.identity);
        activeBoss.SetActive(true);
        activeBoss.name = "BossShip";
        activeBoss.tag = "Enemy";

        var rend = activeBoss.GetComponent<SpriteRenderer>();
        rend.sprite = CreateLargeFaceSprite();
        rend.color = Color.white;
        rend.sortingOrder = 2;

        var col2d = activeBoss.GetComponent<BoxCollider2D>();
        col2d.isTrigger = true;
        col2d.size = new Vector2(1.8f, 1.2f);

        var rb = activeBoss.GetComponent<Rigidbody2D>();
        rb.gravityScale = 0f;
        rb.constraints = RigidbodyConstraints2D.FreezeRotation;

        var boss = activeBoss.GetComponent<BossShip>();
        boss.SetDirection(Random.value > 0.5f);

        if (AudioManager.Instance != null)
            AudioManager.Instance.PlayExplosion(new Vector3(0f, 6f, 0f));
    }

    private Sprite CreateLargeFaceSprite()
    {
        Texture2D[] textures = Resources.LoadAll<Texture2D>("Faces");
        if (textures != null && textures.Length > 0)
        {
            foreach (Texture2D t in textures)
            {
                if (t.name.Contains("Trump") || t.name.Contains("Donald"))
                    return Sprite.Create(t, new Rect(0, 0, t.width, t.height), new Vector2(0.5f, 0.5f), 50f);
            }
            Texture2D first = textures[0];
            return Sprite.Create(first, new Rect(0, 0, first.width, first.height), new Vector2(0.5f, 0.5f), 50f);
        }
        Texture2D fallback = new Texture2D(128, 128);
        Color[] pixels = new Color[128 * 128];
        for (int i = 0; i < pixels.Length; i++) pixels[i] = new Color(1f, 0.84f, 0f);
        fallback.SetPixels(pixels);
        fallback.Apply();
        return Sprite.Create(fallback, new Rect(0, 0, 128, 128), new Vector2(0.5f, 0.5f), 50f);
    }

    private void ClearEnemies()
    {
        foreach (var e in enemies)
            if (e != null) Destroy(e);
        enemies.Clear();
        if (activeBoss != null) { Destroy(activeBoss); activeBoss = null; }
    }

    private Sprite CreateFaceSprite()
    {
        if (ImageGalleryManager.Instance != null)
        {
            var customFaces = ImageGalleryManager.Instance.GetFaces();
            if (customFaces != null && customFaces.Count > 0)
            {
                Texture2D t = customFaces[Random.Range(0, customFaces.Count)];
                if (t != null)
                    return Sprite.Create(t, new Rect(0, 0, t.width, t.height), new Vector2(0.5f, 0.5f), 100f);
            }
        }
        Texture2D[] textures = Resources.LoadAll<Texture2D>("Faces");
        if (textures != null && textures.Length > 0)
        {
            Texture2D t = textures[Random.Range(0, textures.Length)];
            return Sprite.Create(t, new Rect(0, 0, t.width, t.height), new Vector2(0.5f, 0.5f), 100f);
        }
        Texture2D placeholder = new Texture2D(64, 64);
        Color[] pixels = new Color[64 * 64];
        for (int i = 0; i < pixels.Length; i++) pixels[i] = Color.magenta;
        placeholder.SetPixels(pixels);
        placeholder.Apply();
        return Sprite.Create(placeholder, new Rect(0, 0, 64, 64), new Vector2(0.5f, 0.5f), 100f);
    }

    private void UpdateHud()
    {
        if (scoreText != null) scoreText.text = "Score: " + score;
        if (livesText != null) livesText.text = "Lives: " + lives;
        if (waveText != null) waveText.text = "Wave: " + waveNumber;
        if (comboText != null) comboText.text = "Combo x" + combo;
        if (highScoreText != null) highScoreText.text = "Best: " + highScore;
        if (statusText != null)
        {
            if (CurrentState == GameState.Playing) statusText.text = "Destroy the faces!";
            else if (CurrentState == GameState.GameOver) statusText.text = "Game over";
            else statusText.text = "Tap start to begin";
        }
    }

    private void ShowMenu()
    {
        CurrentState = GameState.Menu;
        if (startPanel != null) startPanel.SetActive(true);
        if (gameOverPanel != null) gameOverPanel.SetActive(false);
        UpdateHud();
    }

    private void HidePanels()
    {
        if (startPanel != null) startPanel.SetActive(false);
        if (gameOverPanel != null) gameOverPanel.SetActive(false);
    }

    private void ShowGameOver()
    {
        if (startPanel != null) startPanel.SetActive(false);
        if (gameOverPanel != null) gameOverPanel.SetActive(true);
        UpdateHud();
    }
}
