using System;
using System.IO;
using UnityEngine;
using EventsAppQuest.Web.Domain;

namespace EventsAppQuest.Web.Application
{
    /// <summary>
    /// Controlador da instalação web para ambiente de teste/staging.
    /// Persiste config em ficheiro local; detecta se já instalado; valida pré-requisitos e conexão (mock quando aplicável).
    /// </summary>
    public static class WebInstallController
    {
        private const string InstallFileName = "web_install_config.json";
        private const string PlayerPrefsInstalledKey = "WebInstall_Installed";
        private const string PlayerPrefsInstalledAtKey = "WebInstall_InstalledAt";

        /// <summary>Diretório onde a config é gravada (gravável em runtime).</summary>
        public static string GetConfigDirectory()
        {
#if UNITY_EDITOR || UNITY_STANDALONE
            return Application.persistentDataPath;
#else
            return Application.persistentDataPath;
#endif
        }

        public static string GetConfigPath()
        {
            return Path.Combine(GetConfigDirectory(), InstallFileName);
        }

        /// <summary>True se o sistema foi marcado como instalado (impede reinstalação acidental).</summary>
        public static bool IsInstalled()
        {
            try
            {
                if (PlayerPrefs.GetInt(PlayerPrefsInstalledKey, 0) == 1)
                    return true;
                var path = GetConfigPath();
                if (File.Exists(path))
                {
                    var json = File.ReadAllText(path);
                    var persisted = JsonUtility.FromJson<WebInstallPersisted>(json);
                    return persisted != null && persisted.IsInstalled;
                }
                return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>Marca instalação como concluída e grava config. Impede reinstalação até reset explícito.</summary>
        public static void MarkInstalled(WebInstallConfig config, bool hasSeededDemoData, string installNotes = null)
        {
            var now = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
            var persisted = new WebInstallPersisted
            {
                IsInstalled = true,
                InstalledAt = now,
                HasSeededDemoData = hasSeededDemoData,
                InstallNotes = installNotes ?? "Staging install",
                Config = config ?? new WebInstallConfig()
            };
            try
            {
                var dir = GetConfigDirectory();
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                var path = GetConfigPath();
                File.WriteAllText(path, JsonUtility.ToJson(persisted, true));
                PlayerPrefs.SetInt(PlayerPrefsInstalledKey, 1);
                PlayerPrefs.SetString(PlayerPrefsInstalledAtKey, now);
                PlayerPrefs.Save();
            }
            catch (Exception ex)
            {
                Debug.LogWarning("WebInstall: could not write config file: " + ex.Message);
                PlayerPrefs.SetInt(PlayerPrefsInstalledKey, 1);
                PlayerPrefs.SetString(PlayerPrefsInstalledAtKey, now);
                PlayerPrefs.Save();
            }
        }

        /// <summary>Obtém estado atual (instalado, config, etc.).</summary>
        public static WebInstallState GetState()
        {
            var state = new WebInstallState
            {
                IsInstalled = IsInstalled(),
                CurrentStep = 0,
                HasDatabaseConnection = false,
                HasSeededDemoData = false,
                InstalledAt = null,
                InstallNotes = null,
                Config = null
            };
            try
            {
                var path = GetConfigPath();
                if (File.Exists(path))
                {
                    var json = File.ReadAllText(path);
                    var persisted = JsonUtility.FromJson<WebInstallPersisted>(json);
                    if (persisted != null)
                    {
                        state.HasSeededDemoData = persisted.HasSeededDemoData;
                        state.InstalledAt = persisted.InstalledAt;
                        state.InstallNotes = persisted.InstallNotes;
                        state.Config = persisted.Config;
                    }
                }
                if (state.InstalledAt == null && IsInstalled())
                    state.InstalledAt = PlayerPrefs.GetString(PlayerPrefsInstalledAtKey, null);
                return state;
            }
            catch
            {
                return state;
            }
        }

        /// <summary>Obtém config gravada (null se não instalado).</summary>
        public static WebInstallConfig GetConfig()
        {
            var state = GetState();
            return state.Config;
        }

        /// <summary>Requisitos para staging: diretório gravável e config mínima. Em staging não exige BD real.</summary>
        public static (bool ok, string message) CheckRequirements()
        {
            try
            {
                var dir = GetConfigDirectory();
                if (string.IsNullOrEmpty(dir))
                    return (false, "Directório de config não disponível.");
                if (!Directory.Exists(dir))
                {
                    try { Directory.CreateDirectory(dir); }
                    catch (Exception e) { return (false, "Não foi possível criar diretório: " + e.Message); }
                }
                var testFile = Path.Combine(dir, ".web_install_write_test");
                try
                {
                    File.WriteAllText(testFile, "test");
                    File.Delete(testFile);
                }
                catch (Exception e)
                {
                    return (false, "Directório não gravável: " + e.Message);
                }
                return (true, "Pré-requisitos OK (staging).");
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }

        /// <summary>Valida conexão com banco. Em staging: verifica se campos estão preenchidos; conexão real opcional.</summary>
        public static (bool ok, string message) ValidateDatabaseConnection(WebInstallConfig config)
        {
            if (config == null)
                return (false, "Config não fornecida.");
            if (string.IsNullOrWhiteSpace(config.DatabaseHost) && string.IsNullOrWhiteSpace(config.DatabaseName))
                return (true, "Staging: sem banco configurado (uso mock).");
            if (string.IsNullOrWhiteSpace(config.DatabaseHost))
                return (false, "Indique o host do banco.");
            if (string.IsNullOrWhiteSpace(config.DatabaseName))
                return (false, "Indique o nome da base de dados.");
            // Não há driver real nesta etapa; consideramos "válido" se os campos existirem.
            return (true, "Config de banco preenchida (conexão real não testada em staging).");
        }

        /// <summary>Reset explícito para permitir reinstalação (apenas para teste).</summary>
        public static void ResetInstallation()
        {
            try
            {
                PlayerPrefs.DeleteKey(PlayerPrefsInstalledKey);
                PlayerPrefs.DeleteKey(PlayerPrefsInstalledAtKey);
                PlayerPrefs.Save();
                var path = GetConfigPath();
                if (File.Exists(path))
                    File.Delete(path);
            }
            catch (Exception ex)
            {
                Debug.LogWarning("WebInstall reset: " + ex.Message);
            }
        }
    }
}
