using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public enum FloorType
{
    NormalBattle,
    EliteBattle,
    BossBattle,
    Event
}

public enum EventType
{
    Shop,
    Rest,
    Blacksmith,
    RPG
}

[System.Serializable]
public class LevelData
{
    public FloorType Type;
    public EventType? EventType;
    public int EnemyCount;
    public int LevelStep;
    public bool IsUnlocked;
    public bool IsCompleted;
    public int FloorIndex;
    public int LevelIndex;
}

[System.Serializable]
public class FloorData
{
    public FloorType Type;
    public List<LevelData> Levels = new List<LevelData>();
}

public class GameStructureManager : MonoBehaviour
{
    public static GameStructureManager Instance;

    [SerializeField] private int realmCount = 6;
    [SerializeField] private int floorsPerRealm = 10;
    [SerializeField] private int levelsPerFloor = 3;
    [SerializeField] private int totalEliteBattles = 30;

    private Dictionary<string, List<FloorData>> gameStructure = new Dictionary<string, List<FloorData>>();
    private Dictionary<string, int> realmCompletionAmount = new Dictionary<string, int>();
    private (string realm, int floor, int level) currentLevel;

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

    private void GenerateGameStructure()
    {
        string[] realmNames = { "Fire", "Water", "Earth", "Air", "Light", "Dark" };
        
        for (int r = 0; r < realmCount; r++)
        {
            List<FloorData> realm = new List<FloorData>();
            int eliteBattlesInRealm = totalEliteBattles / realmCount;

            for (int f = 0; f < floorsPerRealm; f++)
            {
                FloorData floor = new FloorData();
                
                // Set floor type
                if (f == 0)
                    floor.Type = FloorType.NormalBattle;
                else if (f == floorsPerRealm - 1)
                    floor.Type = FloorType.BossBattle;
                else if (f == 2)
                    floor.Type = FloorType.Event;
                else
                    floor.Type = (FloorType)UnityEngine.Random.Range(0, 3); // Exclude BossBattle

                // Generate levels for the floor
                for (int l = 0; l < (floor.Type == FloorType.BossBattle ? 1 : levelsPerFloor); l++)
                {
                    LevelData level = new LevelData
                    {
                        Type = floor.Type,
                        LevelStep = f,
                        FloorIndex = f,
                        LevelIndex = l,
                        IsUnlocked = (f == 0 && l == 0), // Only the first level of the first floor is initially unlocked
                        IsCompleted = false
                    };

                    if (level.Type == FloorType.Event)
                    {
                        level.EventType = (EventType)UnityEngine.Random.Range(0, 4);
                    }
                    else if (level.Type == FloorType.NormalBattle || level.Type == FloorType.EliteBattle)
                    {
                        level.EnemyCount = UnityEngine.Random.Range(1, 6);
                    }

                    floor.Levels.Add(level);
                }

                // Distribute elite battles
                if (floor.Type != FloorType.BossBattle && floor.Type != FloorType.Event && eliteBattlesInRealm > 0)
                {
                    int eliteCount = Mathf.Min(eliteBattlesInRealm, levelsPerFloor - 1);
                    for (int e = 0; e < eliteCount; e++)
                    {
                        int randomIndex = UnityEngine.Random.Range(0, floor.Levels.Count);
                        floor.Levels[randomIndex].Type = FloorType.EliteBattle;
                        eliteBattlesInRealm--;
                    }
                }

                realm.Add(floor);
            }

            gameStructure.Add(realmNames[r], realm);
            realmCompletionAmount.Add(realmNames[r], 0);
        }
    }

    public LevelData GetLevelData(string realmName, int floorIndex, int levelIndex)
    {
        if (gameStructure.TryGetValue(realmName, out List<FloorData> realm))
        {
            if (floorIndex >= 0 && floorIndex < realm.Count)
            {
                FloorData floor = realm[floorIndex];
                if (levelIndex >= 0 && levelIndex < floor.Levels.Count)
                {
                    return floor.Levels[levelIndex];
                }
            }
        }
        return null;
    }

    public void UpdateLevelStatus(string realmName, int floorIndex, int levelIndex, bool isUnlocked, bool isCompleted)
    {
        LevelData level = GetLevelData(realmName, floorIndex, levelIndex);
        if (level != null)
        {
            level.IsUnlocked = isUnlocked;
            level.IsCompleted = isCompleted;
        }
    }

    public void SetEnteredLevel(string realmName, int floorIndex, int levelIndex)
    {
        currentLevel = (realmName, floorIndex, levelIndex);
    }

    public List<LevelData> GetNextLevels(string realmName, int floorIndex, int levelIndex)
    {
        List<LevelData> nextLevels = new List<LevelData>();

        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            if (floorIndex >= 0 && floorIndex < realm.Count - 1)
            {
                var nextFloor = realm[floorIndex + 1];
                nextLevels.AddRange(nextFloor.Levels);
            }
        }

        return nextLevels;
    }

    public void UnlockLevel(string realmName, int floorIndex, int levelIndex)
    {
        LevelData level = GetLevelData(realmName, floorIndex, levelIndex);
        if (level != null)
        {
            level.IsUnlocked = true;
        }
    }

    public bool IsRealmCompleted(string realmName)
    {
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            return realm.All(floor => floor.Levels.All(level => level.IsCompleted));
        }
        return false;
    }

    public void ResetRealm(string realmName)
    {
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            foreach (var floor in realm)
            {
                foreach (var level in floor.Levels)
                {
                    level.IsUnlocked = false;
                    level.IsCompleted = false;
                }
            }
            
            // Unlock the first level of the first floor
            if (realm.Count > 0 && realm[0].Levels.Count > 0)
            {
                realm[0].Levels[0].IsUnlocked = true;
            }

            // Increment realm completion amount
            realmCompletionAmount[realmName]++;
        }
    }

    public void LockLevelsInStep(string realmName, int levelStep)
    {
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            foreach (var floor in realm)
            {
                foreach (var level in floor.Levels)
                {
                    if (level.LevelStep == levelStep && !level.IsCompleted)
                    {
                        level.IsUnlocked = false;
                    }
                }
            }
        }
    }

    public int GetRealmCompletionAmount(string realmName)
    {
        if (realmCompletionAmount.TryGetValue(realmName, out int amount))
        {
            return amount;
        }
        return 0;
    }

    public bool IsPreviousLevelCompleted(string realmName, int floorIndex, int levelIndex)
    {
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            if (floorIndex > 0)
            {
                var previousFloor = realm[floorIndex - 1];
                return previousFloor.Levels.All(level => level.IsCompleted);
            }
            else if (levelIndex > 0)
            {
                return realm[floorIndex].Levels[levelIndex - 1].IsCompleted;
            }
        }
        return true; // First level of the first floor is always considered "unlocked"
    }

    public FloorType GetFloorType(string realmName, int floorIndex)
    {
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            if (floorIndex >= 0 && floorIndex < realm.Count)
            {
                return realm[floorIndex].Type;
            }
        }
        return FloorType.NormalBattle; // Default to normal battle if not found
    }

    // Method to get all levels in a realm
    public List<LevelData> GetAllLevelsInRealm(string realmName)
    {
        List<LevelData> allLevels = new List<LevelData>();
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            foreach (var floor in realm)
            {
                allLevels.AddRange(floor.Levels);
            }
        }
        return allLevels;
    }

    // Method to get the current level data
    public LevelData GetCurrentLevelData()
    {
        return GetLevelData(currentLevel.realm, currentLevel.floor, currentLevel.level);
    }

    // Method to check if a level is unlocked
    public bool IsLevelUnlocked(string realmName, int floorIndex, int levelIndex)
    {
        LevelData level = GetLevelData(realmName, floorIndex, levelIndex);
        return level != null && level.IsUnlocked;
    }

    // Method to get the number of completed levels in a realm
    public int GetCompletedLevelCount(string realmName)
    {
        int count = 0;
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            count = realm.Sum(floor => floor.Levels.Count(level => level.IsCompleted));
        }
        return count;
    }

    // Method to get the total number of levels in a realm
    public int GetTotalLevelCount(string realmName)
    {
        int count = 0;
        if (gameStructure.TryGetValue(realmName, out var realm))
        {
            count = realm.Sum(floor => floor.Levels.Count);
        }
        return count;
    }
}

i am currently making a unity game in c# and trying to add this file and logic to my existing project. in my current project i have a level script which i have on every level object that decides the status of itself. but with this file and its logic the level system logic is starting to get more central, since before i was getting and calculating each levels status on the level script attached to each level but now the file above has logic for accessing statuses of all levels and i also would like to make it more centralized like this rather than executing 10-15 scripts, here is my current level script as well. what would you recommend and do in my situation and also share the final code files as well thank you.

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

public class Level : MonoBehaviour, IDataPersistence
{
    [SerializeField] private int levelName;
    [SerializeField] private int levelStep;
    [SerializeField] private bool isUnlocked;
    
    public bool IsUnlocked
    {
        get => isUnlocked;
        set => isUnlocked = value;
    }

    [SerializeField] private bool isCompleted;
    [SerializeField] private List<GameObject> nextNeighbors;

    private static int lastCompleted;
    private static int enteredLevel;
    private static int fireCompletionAmount;


    private void Awake()
    {
        levelName = Convert.ToInt32(gameObject.name);
        GetComponent<Image>().alphaHitTestMinimumThreshold = 0.01f;
    }

    private void Start()
    {
        if (levelName == 1 && !isCompleted)
        {
            isUnlocked = true;
        }
        CompleteLevel();
        UpdateLevelButton();
    }
    
    public void LoadData(GameData data)
    {
        if (data.fireRealmLevels.TryGetValue(levelName, out int levelStatus))
        {
            isUnlocked = levelStatus != 0;
            isCompleted = levelStatus == 2;
        }
        else
        {
            isUnlocked = false;
            isCompleted = false;
        }
        
        lastCompleted = data.fireLastCompleted;
        fireCompletionAmount = data.fireCompletionAmount;
    }
    
    public void SaveData(GameData data)
    {
        data.fireCompletionAmount = fireCompletionAmount;
        
        if (data.fireRealmLevels.ContainsKey(levelName))
        {
            data.fireRealmLevels.Remove(levelName);
        }
        data.fireRealmLevels.Add(levelName, isCompleted ? 2 : isUnlocked ? 1 : 0);
        
        data.fireLastCompleted = lastCompleted;
        data.fireEnteredLevel = enteredLevel;
    }
    
    private void UpdateLevelButton()
    {
        if (isUnlocked)
        {
            
            if (isCompleted)
            {
                GetComponent<Button>().interactable = false;
                GetComponent<Image>().color = new Color(0f, 0f, 1f, 0.5f);
            }
            else
            {
                GetComponent<Button>().interactable = true;
                GetComponent<Image>().color = new Color(1f, 1f, 1f);
            }
        }
        else
        {
            GetComponent<Button>().interactable = false;
            GetComponent<Image>().color = new Color(0.5f, 0.5f, 0.5f, 0f);
        }
    }

    public void LoadLevel(string levelToLoad)
    {
        Debug.Log(levelToLoad);
        enteredLevel = Convert.ToInt32(gameObject.name);
        DataPersistenceManager.instance.LoadSceneAsync(levelToLoad);
    }
    
    public void CompleteLevel()
    {
        if (levelName == lastCompleted)
        {
            Level[] levels = FindObjectsOfType<Level>();
            if (nextNeighbors.Count == 0)
            {
                fireCompletionAmount++;
                
                foreach (Level level in levels)
                {
                    level.isUnlocked = false;
                    level.isCompleted = false;
                    lastCompleted = 0;
                    level.UpdateLevelButton();
                }

                DataPersistenceManager.instance.LoadSceneAsync("RealmSelect");
                return;
            }
            
            // logic to lock the levels in the same step, every level has a step written as levelStep integer
            
            foreach (Level level in levels)
            {
                if (level.levelStep == levelStep && !level.isCompleted)
                {
                    level.isUnlocked = false;
                    level.UpdateLevelButton();
                }
            }
            
            foreach (GameObject neighbor in nextNeighbors)
            {
                Level neighborLevel = neighbor.GetComponent<Level>();
                neighborLevel.IsUnlocked = true;
                neighborLevel.UpdateLevelButton(); // Update button state
            }
        }
    }
}