// ==============================================
// TrackGenerator.cs - Endlose Streckengenerierung
// ==============================================
// Erzeugt endlose Streckenabschnitte durch
// Object-Pooling und Recycling.

using System.Collections.Generic;
using UnityEngine;

namespace BreakpilotDrive
{
    public class TrackGenerator : MonoBehaviour
    {
        public static TrackGenerator Instance { get; private set; }

        [Header("Track Prefabs")]
        [SerializeField] private GameObject[] trackSegmentPrefabs;  // Verschiedene Streckenabschnitte
        [SerializeField] private GameObject startSegmentPrefab;     // Start-Segment

        [Header("Generierung")]
        [SerializeField] private float segmentLength = 50f;         // Laenge eines Segments
        [SerializeField] private int visibleSegments = 5;           // Anzahl sichtbarer Segmente
        [SerializeField] private float despawnDistance = -20f;      // Wann Segment recycelt wird

        [Header("Bewegung")]
        [SerializeField] private float baseSpeed = 10f;             // Basis-Geschwindigkeit
        private float currentSpeed;

        // Object Pool
        private List<GameObject> activeSegments = new List<GameObject>();
        private Queue<GameObject> segmentPool = new Queue<GameObject>();

        // Position
        private float nextSpawnZ = 0f;

        void Awake()
        {
            if (Instance == null)
            {
                Instance = this;
            }
            else
            {
                Destroy(gameObject);
            }
        }

        void Start()
        {
            currentSpeed = baseSpeed;

            // Geschwindigkeit von Difficulty laden
            if (GameManager.Instance?.DifficultySettings != null)
            {
                currentSpeed = GameManager.Instance.DifficultySettings.lane_speed;
            }

            // Initiale Segmente erstellen
            InitializeTrack();
        }

        void Update()
        {
            if (GameManager.Instance?.CurrentState != GameState.Playing)
                return;

            // Segmente bewegen
            MoveSegments();

            // Alte Segmente recyceln
            RecycleSegments();

            // Neue Segmente spawnen
            SpawnSegmentsIfNeeded();
        }

        // ==============================================
        // Initialisierung
        // ==============================================
        private void InitializeTrack()
        {
            nextSpawnZ = 0f;

            // Start-Segment
            if (startSegmentPrefab != null)
            {
                SpawnSegment(startSegmentPrefab);
            }

            // Weitere Segmente fuer sichtbaren Bereich
            for (int i = 0; i < visibleSegments; i++)
            {
                SpawnRandomSegment();
            }
        }

        // ==============================================
        // Segment-Spawning
        // ==============================================
        private void SpawnRandomSegment()
        {
            if (trackSegmentPrefabs == null || trackSegmentPrefabs.Length == 0)
            {
                Debug.LogWarning("Keine Track-Segment-Prefabs zugewiesen!");
                return;
            }

            int index = Random.Range(0, trackSegmentPrefabs.Length);
            SpawnSegment(trackSegmentPrefabs[index]);
        }

        private void SpawnSegment(GameObject prefab)
        {
            GameObject segment;

            // Aus Pool holen oder neu erstellen
            if (segmentPool.Count > 0)
            {
                segment = segmentPool.Dequeue();
                segment.SetActive(true);
            }
            else
            {
                segment = Instantiate(prefab, transform);
            }

            // Position setzen
            segment.transform.position = new Vector3(0, 0, nextSpawnZ);
            nextSpawnZ += segmentLength;

            activeSegments.Add(segment);

            // Hindernisse und Items auf Segment spawnen
            ObstacleSpawner.Instance?.SpawnOnSegment(segment, nextSpawnZ - segmentLength);
        }

        private void SpawnSegmentsIfNeeded()
        {
            // Pruefe ob wir mehr Segmente brauchen
            float playerZ = 0; // Spieler ist bei Z=0, Welt bewegt sich
            float maxVisibleZ = playerZ + (visibleSegments * segmentLength);

            while (nextSpawnZ < maxVisibleZ)
            {
                SpawnRandomSegment();
            }
        }

        // ==============================================
        // Bewegung
        // ==============================================
        private void MoveSegments()
        {
            Vector3 movement = Vector3.back * currentSpeed * Time.deltaTime;

            foreach (var segment in activeSegments)
            {
                segment.transform.position += movement;
            }

            // Auch nextSpawnZ anpassen
            nextSpawnZ -= currentSpeed * Time.deltaTime;
        }

        // ==============================================
        // Recycling
        // ==============================================
        private void RecycleSegments()
        {
            for (int i = activeSegments.Count - 1; i >= 0; i--)
            {
                if (activeSegments[i].transform.position.z < despawnDistance)
                {
                    RecycleSegment(activeSegments[i]);
                    activeSegments.RemoveAt(i);
                }
            }
        }

        private void RecycleSegment(GameObject segment)
        {
            // Kinder-Objekte (Hindernisse, Items) entfernen
            foreach (Transform child in segment.transform)
            {
                if (child.CompareTag("Obstacle") || child.CompareTag("Coin") ||
                    child.CompareTag("Star") || child.CompareTag("QuizTrigger"))
                {
                    Destroy(child.gameObject);
                }
            }

            // Segment deaktivieren und zurueck in Pool
            segment.SetActive(false);
            segmentPool.Enqueue(segment);
        }

        // ==============================================
        // Geschwindigkeit
        // ==============================================
        public void SetSpeed(float speed)
        {
            currentSpeed = speed;
        }

        public float GetSpeed()
        {
            return currentSpeed;
        }

        public void IncreaseSpeed(float amount)
        {
            currentSpeed += amount;
        }

        // ==============================================
        // Reset
        // ==============================================
        public void ResetTrack()
        {
            // Alle aktiven Segmente recyceln
            foreach (var segment in activeSegments)
            {
                RecycleSegment(segment);
            }
            activeSegments.Clear();

            // Neu initialisieren
            nextSpawnZ = 0f;
            currentSpeed = baseSpeed;
            InitializeTrack();
        }
    }
}
