using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using EventsAppQuest.Web.Application;
using EventsAppQuest.Web.Domain;

namespace EventsAppQuest.Web.Presentation
{
    /// <summary>
    /// Bootstrap do instalador web: se já instalado redireciona para o dashboard; senão mostra o wizard de instalação.
    /// Colocar numa cena de instalação (ex.: WebInstall) como ponto de entrada para staging.
    /// </summary>
    public class WebInstallBootstrap : MonoBehaviour
    {
        private const string DashboardSceneName = "HotelCRM";
        private const int StepWelcome = 0;
        private const int StepRequirements = 1;
        private const int StepDatabase = 2;
        private const int StepApp = 3;
        private const int StepDemo = 4;
        private const int StepFinish = 5;
        private const int StepCount = 6;

        private Canvas _canvas;
        private Transform _root;
        private Transform _stepContent;
        private Text _titleText;
        private int _currentStep;
        private Font _font;

        private string _appName = "EventsAppQuest Web";
        private string _appUrl = "http://localhost";
        private string _dbHost = "localhost";
        private string _dbPort = "5432";
        private string _dbName = "eventsapp_web";
        private string _dbUser = "";
        private string _dbPass = "";
        private bool _seedDemo = true;
        private string _testAdminName = "admin";

        private void Start()
        {
            if (WebInstallController.IsInstalled())
            {
                SceneManager.LoadScene(DashboardSceneName);
                return;
            }
            _font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
            _currentStep = StepWelcome;
            CreateInstallCanvas();
            RenderStep();
        }

        private void CreateInstallCanvas()
        {
            var go = new GameObject("WebInstallCanvas");
            _canvas = go.AddComponent<Canvas>();
            _canvas.renderMode = RenderMode.ScreenSpaceOverlay;
            go.AddComponent<CanvasScaler>().uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
            go.GetComponent<CanvasScaler>().referenceResolution = new Vector2(1920, 1080);
            go.AddComponent<GraphicRaycaster>();

            var rootGo = new GameObject("Root");
            rootGo.transform.SetParent(go.transform, false);
            var rt = rootGo.AddComponent<RectTransform>();
            rt.anchorMin = Vector2.zero;
            rt.anchorMax = Vector2.one;
            rt.offsetMin = new Vector2(80, 80);
            rt.offsetMax = new Vector2(-80, -80);
            _root = rootGo.transform;
            var vlg = rootGo.AddComponent<VerticalLayoutGroup>();
            vlg.spacing = 12;
            vlg.padding = new RectOffset(24, 24, 24, 24);
            vlg.childForceExpandWidth = true;
            vlg.childForceExpandHeight = false;

            var bg = rootGo.AddComponent<Image>();
            bg.color = new Color(0.95f, 0.96f, 0.98f, 1f);

            var titleGo = new GameObject("Title");
            titleGo.transform.SetParent(_root, false);
            _titleText = titleGo.AddComponent<Text>();
            _titleText.text = "Instalação — Ambiente de teste/staging";
            _titleText.font = _font;
            _titleText.fontSize = 24;
            _titleText.fontStyle = FontStyle.Bold;
            var titleLe = titleGo.AddComponent<LayoutElement>();
            titleLe.preferredHeight = 36;

            var stepContentGo = new GameObject("StepContent");
            stepContentGo.transform.SetParent(_root, false);
            var stepLe = stepContentGo.AddComponent<LayoutElement>();
            stepLe.flexibleHeight = 1;
            stepLe.minHeight = 300;
            var stepVlg = stepContentGo.AddComponent<VerticalLayoutGroup>();
            stepVlg.spacing = 8;
            stepVlg.childForceExpandWidth = true;
            _stepContent = stepContentGo.transform;
        }

        private void ClearStepContent()
        {
            for (var i = _stepContent.childCount - 1; i >= 0; i--)
                Destroy(_stepContent.GetChild(i).gameObject);
        }

        private static string GetStepName(int step)
        {
            if (step == StepWelcome) return "Bem-vindo";
            if (step == StepRequirements) return "Pré-requisitos";
            if (step == StepDatabase) return "Base de dados";
            if (step == StepApp) return "Aplicação";
            if (step == StepDemo) return "Dados demo";
            if (step == StepFinish) return "Concluir";
            return "—";
        }

        private void RenderStep()
        {
            if (_titleText != null)
                _titleText.text = "Instalação — Passo " + (_currentStep + 1) + " de " + StepCount + " — " + GetStepName(_currentStep);
            ClearStepContent();
            if (_currentStep == StepWelcome) RenderWelcome();
            else if (_currentStep == StepRequirements) RenderRequirements();
            else if (_currentStep == StepDatabase) RenderDatabase();
            else if (_currentStep == StepApp) RenderApp();
            else if (_currentStep == StepDemo) RenderDemo();
            else if (_currentStep == StepFinish) RenderFinish();
            AddNavigationButtons();
        }

        private void RenderWelcome()
        {
            AddLabel("Bem-vindo ao instalador da camada Web (teste/staging).");
            AddLabel("Este assistente configura o ambiente local para visualizar e testar o CRM do hotel, painel do produtor e dashboard consolidado.");
            AddLabel("Nenhuma alteração é feita na camada Quest.");
        }

        private void RenderRequirements()
        {
            var (ok, message) = WebInstallController.CheckRequirements();
            AddLabel("Verificação de pré-requisitos:");
            AddLabel(ok ? "OK: " + message : "Aviso: " + message);
            if (!ok)
                AddLabel("Corrija o problema antes de avançar ou use outro diretório.");
        }

        private InputField AddInput(string label, string value, bool password = false)
        {
            var row = new GameObject("Row");
            row.transform.SetParent(_stepContent, false);
            var rowLe = row.AddComponent<LayoutElement>();
            rowLe.preferredHeight = 32;
            var hlg = row.AddComponent<HorizontalLayoutGroup>();
            hlg.spacing = 8;
            hlg.childForceExpandWidth = true;

            var labelGo = new GameObject("Label");
            labelGo.transform.SetParent(row.transform, false);
            var labelLe = labelGo.AddComponent<LayoutElement>();
            labelLe.preferredWidth = 180;
            var labelText = labelGo.AddComponent<Text>();
            labelText.text = label;
            labelText.font = _font;
            labelText.fontSize = 12;

            var inputGo = new GameObject("Input");
            inputGo.transform.SetParent(row.transform, false);
            var inputLe = inputGo.AddComponent<LayoutElement>();
            inputLe.flexibleWidth = 1;
            inputLe.preferredHeight = 28;
            var inputBg = inputGo.AddComponent<Image>();
            inputBg.color = Color.white;
            var input = inputGo.AddComponent<InputField>();
            input.contentType = password ? InputField.ContentType.Password : InputField.ContentType.Standard;
            input.text = value ?? "";

            var textGo = new GameObject("Text");
            textGo.transform.SetParent(inputGo.transform, false);
            var textRt = textGo.AddComponent<RectTransform>();
            textRt.anchorMin = Vector2.zero;
            textRt.anchorMax = Vector2.one;
            textRt.offsetMin = new Vector2(4, 2);
            textRt.offsetMax = new Vector2(-4, -2);
            var text = textGo.AddComponent<Text>();
            text.font = _font;
            text.fontSize = 11;
            input.textComponent = text;
            return input;
        }

        private void AddLabel(string text)
        {
            var go = new GameObject("Label");
            go.transform.SetParent(_stepContent, false);
            var t = go.AddComponent<Text>();
            t.text = text;
            t.font = _font;
            t.fontSize = 13;
            go.AddComponent<LayoutElement>().preferredHeight = 22;
        }

        private void RenderDatabase()
        {
            if (!string.IsNullOrEmpty(_lastError))
            {
                var err = new GameObject("Error");
                err.transform.SetParent(_stepContent, false);
                var t = err.AddComponent<Text>();
                t.text = _lastError;
                t.font = _font;
                t.fontSize = 12;
                t.color = new Color(0.7f, 0.2f, 0.2f);
                err.AddComponent<LayoutElement>().preferredHeight = 20;
            }
            AddLabel("Configuração de base de dados (opcional em staging; pode deixar em branco para usar apenas dados mock):");
            _inputDbHost = AddInput("Database Host", _dbHost);
            _inputDbPort = AddInput("Database Port", _dbPort);
            _inputDbName = AddInput("Database Name", _dbName);
            _inputDbUser = AddInput("Database Username", _dbUser);
            _inputDbPass = AddInput("Database Password", _dbPass, true);
        }

        private void RenderApp()
        {
            AddLabel("Dados básicos da aplicação:");
            _inputAppName = AddInput("App Name", _appName);
            _inputAppUrl = AddInput("App URL", _appUrl);
        }

        private void RenderDemo()
        {
            AddLabel("Dados de demonstração:");
            AddLabel("Se activar, o dashboard será preenchido com leads, oportunidades, propostas e sessões de exemplo.");
            var row = new GameObject("Row");
            row.transform.SetParent(_stepContent, false);
            var hlg = row.AddComponent<HorizontalLayoutGroup>();
            hlg.spacing = 8;
            var toggleGo = new GameObject("Toggle");
            toggleGo.transform.SetParent(row.transform, false);
            var toggle = toggleGo.AddComponent<Toggle>();
            toggle.isOn = _seedDemo;
            var toggleLe = toggleGo.AddComponent<LayoutElement>();
            toggleLe.preferredWidth = 24;
            toggleLe.preferredHeight = 24;
            var bg = toggleGo.AddComponent<Image>();
            bg.color = new Color(0.9f, 0.9f, 0.9f);
            var checkGo = new GameObject("Checkmark");
            checkGo.transform.SetParent(toggleGo.transform, false);
            var checkRt = checkGo.AddComponent<RectTransform>();
            checkRt.anchorMin = Vector2.zero;
            checkRt.anchorMax = Vector2.one;
            checkRt.offsetMin = Vector2.one * 4;
            checkRt.offsetMax = Vector2.one * -4;
            var checkImg = checkGo.AddComponent<Image>();
            checkImg.color = new Color(0.2f, 0.6f, 0.2f);
            toggle.graphic = checkImg;
            toggle.targetGraphic = bg;
            _toggleSeedDemo = toggle;
            var labelGo = new GameObject("Label");
            labelGo.transform.SetParent(row.transform, false);
            var labelText = labelGo.AddComponent<Text>();
            labelText.text = " Popular dados mock/demo de demonstração";
            labelText.font = _font;
            labelText.fontSize = 12;

            AddLabel("Admin de teste (opcional):");
            _inputTestAdmin = AddInput("Nome/identificador do admin de teste", _testAdminName);
        }

        private void RenderFinish()
        {
            AddLabel("Resumo:");
            AddLabel($"App: {_appName} | URL: {_appUrl}");
            AddLabel($"Base de dados: {(_dbHost ?? "—")}:{(_dbPort ?? "—")} / {(_dbName ?? "—")}");
            AddLabel($"Dados demo: {(_seedDemo ? "Sim" : "Não")}");
            AddLabel("Clique em Concluir para gravar a configuração e abrir o dashboard.");
        }

        private InputField _inputDbHost, _inputDbPort, _inputDbName, _inputDbUser, _inputDbPass;
        private InputField _inputAppName, _inputAppUrl;
        private InputField _inputTestAdmin;
        private Toggle _toggleSeedDemo;
        private string _lastError;

        private void SaveCurrentStepValues()
        {
            if (_currentStep == StepDatabase && _inputDbHost != null)
            {
                _dbHost = _inputDbHost.text ?? "";
                _dbPort = _inputDbPort != null ? _inputDbPort.text ?? "" : _dbPort;
                _dbName = _inputDbName != null ? _inputDbName.text ?? "" : _dbName;
                _dbUser = _inputDbUser != null ? _inputDbUser.text ?? "" : _dbUser;
                _dbPass = _inputDbPass != null ? _inputDbPass.text ?? "" : _dbPass;
            }
            else if (_currentStep == StepApp && _inputAppName != null)
            {
                _appName = _inputAppName.text ?? _appName;
                _appUrl = _inputAppUrl != null ? _inputAppUrl.text ?? _appUrl : _appUrl;
            }
            else if (_currentStep == StepDemo && _toggleSeedDemo != null)
            {
                _seedDemo = _toggleSeedDemo.isOn;
                if (_inputTestAdmin != null) _testAdminName = _inputTestAdmin.text ?? _testAdminName;
            }
        }

        private void AddNavigationButtons()
        {
            var row = new GameObject("NavRow");
            row.transform.SetParent(_stepContent, false);
            var hlg = row.AddComponent<HorizontalLayoutGroup>();
            hlg.spacing = 12;
            hlg.childForceExpandWidth = false;

            if (_currentStep > StepWelcome)
                AddButton(row.transform, "Anterior", () => { SaveCurrentStepValues(); _currentStep--; RenderStep(); });

            if (_currentStep < StepFinish)
                AddButton(row.transform, "Seguinte", () => OnNext());
            else
                AddButton(row.transform, "Concluir", () => OnFinish());
        }

        private void OnNext()
        {
            SaveCurrentStepValues();
            if (_currentStep == StepRequirements)
            {
                var (ok, _) = WebInstallController.CheckRequirements();
                if (!ok) return;
            }
            if (_currentStep == StepDatabase)
            {
                var config = BuildConfig();
                var (ok, msg) = WebInstallController.ValidateDatabaseConnection(config);
                if (!ok) { _lastError = "Validação: " + msg; RenderStep(); return; }
            }
            _lastError = null;
            _currentStep++;
            RenderStep();
        }

        private void OnFinish()
        {
            SaveCurrentStepValues();
            var config = BuildConfig();
            WebInstallController.MarkInstalled(config, _seedDemo, "Instalação staging concluída.");
            SceneManager.LoadScene(DashboardSceneName);
        }

        private WebInstallConfig BuildConfig()
        {
            return new WebInstallConfig
            {
                AppName = _appName ?? "EventsAppQuest Web",
                AppUrl = _appUrl ?? "http://localhost",
                DatabaseHost = _dbHost ?? "",
                DatabasePort = _dbPort ?? "5432",
                DatabaseName = _dbName ?? "",
                DatabaseUsername = _dbUser ?? "",
                DatabasePassword = _dbPass ?? "",
                SeedDemoData = _seedDemo,
                TestAdminName = _testAdminName ?? ""
            };
        }

        private void AddButton(Transform parent, string label, Action onClick)
        {
            var go = new GameObject("Btn_" + label);
            go.transform.SetParent(parent, false);
            var le = go.AddComponent<LayoutElement>();
            le.preferredWidth = 120;
            le.preferredHeight = 32;
            var img = go.AddComponent<Image>();
            img.color = new Color(0.35f, 0.65f, 0.9f);
            var btn = go.AddComponent<Button>();
            btn.targetGraphic = img;
            btn.onClick.AddListener(() => onClick?.Invoke());
            var textGo = new GameObject("Text");
            textGo.transform.SetParent(go.transform, false);
            var textRt = textGo.AddComponent<RectTransform>();
            textRt.anchorMin = Vector2.zero;
            textRt.anchorMax = Vector2.one;
            textRt.offsetMin = Vector2.zero;
            textRt.offsetMax = Vector2.zero;
            var text = textGo.AddComponent<Text>();
            text.text = label;
            text.font = _font;
            text.fontSize = 12;
            text.alignment = TextAnchor.MiddleCenter;
        }

        /// <summary>Para teste: permite reabrir o instalador (reset explícito).</summary>
        public static void ResetAndReload()
        {
            WebInstallController.ResetInstallation();
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }
}
