using System.Text.Json;

namespace Lentia.Utils;

public class LauncherSettings {
    public RamSettings Ram { get; set; } = new();
    public string JavaPath { get; set; } = "java";
}

public class RamSettings {
    public int Max { get; set; } = 2048;
}

public static class SettingsManager {
    private static string _launcherDataPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ".lentia");
    private static string SettingsFilePath => Path.Combine(_launcherDataPath, "launcher_settings.json");

    private static readonly LauncherSettings BaseSettings = new();
    private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };

    public static void InitSettings(string path) {
        _launcherDataPath = path;

        if (!Directory.Exists(_launcherDataPath)) {
            Directory.CreateDirectory(_launcherDataPath);
        }
        if (!File.Exists(SettingsFilePath)) {
            Clean();
        }
    }

    public static string GetLauncherDataPath() => _launcherDataPath;

    public static void Clean() {
        string json = JsonSerializer.Serialize(BaseSettings, JsonOptions);
        File.WriteAllText(SettingsFilePath, json);
    }

    public static LauncherSettings ReadSettings() {
        try {
            string json = File.ReadAllText(SettingsFilePath);
            return JsonSerializer.Deserialize<LauncherSettings>(json) ?? BaseSettings;
        } catch {
            Clean();
            return ReadSettings();
        }
    }

    public static void WriteSettings(LauncherSettings settings) {
        try {
            string json = JsonSerializer.Serialize(settings, JsonOptions);
            File.WriteAllText(SettingsFilePath, json);
        } catch {
            Clean();
            WriteSettings(settings);
        }
    }

    public static T? GetValue<T>(string key) {
        try {
            var settings = ReadSettings();
            string[] keys = key.Split(".");
            object current = settings;

            foreach (var k in keys) {
                var property = current.GetType().GetProperty(k);
                if (property == null) throw new Exception($"Clé {k} introuvable.");
                current = property.GetValue(current)!;
            }

            return (T)current;
        } catch {
            Clean();
            return GetValue<T>(key);
        }
    }

    public static void Set(string path, object value) {
        try {
            var settings = ReadSettings();
            string[] properties = path.Split('.');
            object current = settings;

            for (int i = 0; i < properties.Length - 1; i++) {
                var prop = current.GetType().GetProperty(properties[i], 
                    System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
                
                if (prop == null) throw new Exception($"Niveau '{properties[i]}' introuvable.");

                var next = prop.GetValue(current);
                if (next == null) {
                    next = Activator.CreateInstance(prop.PropertyType);
                    prop.SetValue(current, next);
                }
                current = next!;
            }

            var lastProp = current!.GetType().GetProperty(properties[^1], 
                System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);

            if (lastProp == null || !lastProp.CanWrite)
                throw new Exception($"Propriété '{properties[^1]}' introuvable ou verrouillée.");

            object? convertedValue = Convert.ChangeType(value.ToString(), lastProp.PropertyType);
            lastProp.SetValue(current, convertedValue);

            WriteSettings(settings);
        } catch (Exception ex) {
            Console.WriteLine($"[SettingsManager] Erreur Set sur '{path}': {ex.Message}");
        }
    }
}