using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using FairyView;
using StandardScene.Utils;

namespace StandardScene.ExtendDevice.ButtonBox
{
    /// <summary>
    /// 按钮盒配置管理（CycleGUI 版，替代原 WinForms <c>ButtonBoxManager</c> 窗体）。
    /// </summary>
    public class ButtonBoxManager
    {
        private const string DataFileName = "ButtonBoxConfig.json";
        private string DataFilePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
        private readonly object SaveLock = new object();

        private Panel _panel;
        private List<ButtonBoxModel> _boxes = new List<ButtonBoxModel>();
        private int _selectedBoxIdx = -1;
        private int _selectedBtnIdx = -1;
        private string _status = "";

        private string _boxIp = "";
        private string _boxPort = "502";
        private string _boxIndex = "";
        private int _typeIdx;
        private string[] _typeNames = Array.Empty<string>();

        private string _btnIndex = "";
        private string _triggerMission = "";
        private string _triggerMethod = "";
        private string _triggerParams = "";
        private string _triggerDelay = "0";
        private int _triggerStateIdx;
        private readonly string[] _triggerStateNames = Enum.GetNames(typeof(ButtonState));

        private static ButtonBoxManager _instance;

        public static void OpenViewer() => Open();

        public static void Open() => (_instance ??= new ButtonBoxManager()).OpenCore();

        private void OpenCore()
        {
            if (_panel != null)
            {
                try { _panel.BringToFront(); return; }
                catch { _panel = null; }
            }

            _typeNames = DiscoverTypes();
            LoadData();
            _selectedBoxIdx = -1;
            _selectedBtnIdx = -1;
            ClearBoxFields();
            ClearButtonFields();

            var panel = GUI.DeclarePanel()
                .ShowTitle("按钮盒管理")
                .ForceFloat()
                .InitSize(1200, 760)
                .InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f);
            _panel = panel;
            panel.IfTerminalQuit(() => { if (_panel == panel) _panel = null; });

            panel.Define(pb =>
            {
                if (pb.Closing())
                {
                    SaveData();
                    panel.Exit();
                    _panel = null;
                    return;
                }

                pb.SeparatorText("按钮盒");
                pb.Table("btnbox-list", new[] { "盒编码", "IP", "端口", "类型", "盒操作" },
                    _boxes.Count, (row, i) =>
                    {
                        var b = _boxes[i];
                        row.Label($"{b.Index}");
                        row.Label(b.Ip);
                        row.Label($"{b.Port}");
                        row.Label(b.Type);
                        if (row.ButtonGroup(new[] { "选盒" }, new[] { "选择该按钮盒" }) == 0)
                        {
                            _selectedBoxIdx = i;
                            _selectedBtnIdx = -1;
                            LoadBoxFields(b);
                            ClearButtonFields();
                        }
                    }, height: FairyUiHelper.TableHeightPx(8), enableSearch: true);

                pb.SeparatorText("按钮盒编辑");
                var (ip, _) = pb.TextInput("1. IP", _boxIp, alwaysReturnString: true);
                _boxIp = ip;
                pb.SameLine(12);
                var (port, _) = pb.TextInput("2. 端口", _boxPort, alwaysReturnString: true);
                _boxPort = port;
                var (idx, _) = pb.TextInput("3. 盒编码", _boxIndex, alwaysReturnString: true);
                _boxIndex = idx;
                if (_typeNames.Length > 0)
                    pb.DropdownBox("4. 类型", _typeNames, ref _typeIdx);

                if (pb.Button("添加按钮盒", distinct: "bb-add-box")) AddBox();
                pb.SameLine(8);
                if (pb.Button("保存按钮盒", distinct: "bb-save-box")) SaveBox();
                pb.SameLine(8);
                if (pb.Button("删除按钮盒", distinct: "bb-del-box")) ConfirmDeleteBox();

                var buttons = GetSelectedBox()?.Buttons ?? new List<ButtonModel>();
                pb.SeparatorText($"按钮列表（盒 #{GetSelectedBox()?.Index ?? 0}，共 {buttons.Count} 个）");
                pb.Table("btn-list", new[] { "按钮编码", "触发状态", "延迟", "Mission", "Method", "按钮操作" },
                    buttons.Count, (row, i) =>
                    {
                        var btn = buttons[i];
                        row.Label($"{btn.Index}");
                        row.Label(btn.TriggerState);
                        row.Label($"{btn.TriggerDelay}");
                        row.Label(btn.TriggerMission);
                        row.Label(btn.TriggerMethod);
                        if (row.ButtonGroup(new[] { "选按钮" }, new[] { "选择该按钮" }) == 0)
                        {
                            _selectedBtnIdx = i;
                            LoadButtonFields(btn);
                        }
                    }, height: FairyUiHelper.TableHeightPx(6), enableSearch: true);

                pb.SeparatorText("按钮编辑");
                var (bIdx, _) = pb.TextInput("5. 按钮编码", _btnIndex, alwaysReturnString: true);
                _btnIndex = bIdx;
                pb.DropdownBox("6. 触发状态", _triggerStateNames, ref _triggerStateIdx);
                var (delay, _) = pb.TextInput("7. 触发延迟", _triggerDelay, alwaysReturnString: true);
                _triggerDelay = delay;
                var (mission, _) = pb.TextInput("8. TriggerMission", _triggerMission, alwaysReturnString: true);
                _triggerMission = mission;
                var (method, _) = pb.TextInput("9. TriggerMethod", _triggerMethod, alwaysReturnString: true);
                _triggerMethod = method;
                var (parms, _) = pb.TextInput("10. TriggerMethodParams", _triggerParams, alwaysReturnString: true);
                _triggerParams = parms;

                if (pb.Button("添加按钮", distinct: "bb-add-btn")) AddButton();
                pb.SameLine(8);
                if (pb.Button("保存按钮", distinct: "bb-save-btn")) SaveButton();
                pb.SameLine(8);
                if (pb.Button("删除按钮", distinct: "bb-del-btn")) ConfirmDeleteButton();

                if (!string.IsNullOrEmpty(_status))
                {
                    pb.Separator();
                    pb.Label(_status);
                }
            });
        }

        private ButtonBoxModel GetSelectedBox() =>
            _selectedBoxIdx >= 0 && _selectedBoxIdx < _boxes.Count ? _boxes[_selectedBoxIdx] : null;

        private ButtonModel GetSelectedButton()
        {
            var box = GetSelectedBox();
            return box != null && _selectedBtnIdx >= 0 && _selectedBtnIdx < box.Buttons.Count
                ? box.Buttons[_selectedBtnIdx] : null;
        }

        private string[] DiscoverTypes()
        {
            try
            {
                var names = Simple3.Utils.UiTypeDiscovery.AllTypes()
                    .Where(t => t.IsClass && !t.IsAbstract
                        && t.Namespace == typeof(BasicButtonBox).Namespace
                        && t.IsSubclassOf(typeof(BasicButtonBox)))
                    .Select(t => t.Name)
                    .OrderBy(n => n)
                    .ToArray();
                return names.Length > 0 ? names : new[] { "BasicButtonBox" };
            }
            catch
            {
                return new[] { "BasicButtonBox" };
            }
        }

        private void LoadData()
        {
            try
            {
                if (!File.Exists(DataFilePath)) { _boxes = new List<ButtonBoxModel>(); return; }
                var json = File.ReadAllText(DataFilePath, Encoding.UTF8);
                _boxes = string.IsNullOrWhiteSpace(json)
                    ? new List<ButtonBoxModel>()
                    : json.JsonTo<List<ButtonBoxModel>>() ?? new List<ButtonBoxModel>();
            }
            catch (Exception ex)
            {
                _boxes = new List<ButtonBoxModel>();
                _status = $"加载失败: {ex.Message}";
            }
        }

        private void SaveData()
        {
            var json = _boxes.ToJson();
            var path = DataFilePath;
            Task.Run(() =>
            {
                try
                {
                    lock (SaveLock)
                        File.WriteAllText(path, json, Encoding.UTF8);
                }
                catch (Exception ex)
                {
                    _status = $"保存失败: {ex.Message}";
                    _panel?.Repaint();
                }
            });
        }

        private void LoadBoxFields(ButtonBoxModel b)
        {
            _boxIp = b.Ip;
            _boxPort = b.Port.ToString();
            _boxIndex = b.Index.ToString();
            _typeIdx = Math.Max(0, Array.IndexOf(_typeNames, b.Type));
            if (_typeIdx < 0) _typeIdx = 0;
        }

        private void ClearBoxFields()
        {
            _boxIp = "";
            _boxPort = "502";
            _boxIndex = "";
            _typeIdx = 0;
        }

        private void LoadButtonFields(ButtonModel b)
        {
            _btnIndex = b.Index.ToString();
            _triggerMission = b.TriggerMission ?? "";
            _triggerMethod = b.TriggerMethod ?? "";
            _triggerParams = b.TriggerMethodParams ?? "";
            _triggerDelay = b.TriggerDelay.ToString();
            _triggerStateIdx = Math.Max(0, Array.IndexOf(_triggerStateNames, b.TriggerState));
        }

        private void ClearButtonFields()
        {
            _btnIndex = "";
            _triggerMission = "";
            _triggerMethod = "";
            _triggerParams = "";
            _triggerDelay = "0";
            _triggerStateIdx = 0;
        }

        private void AddBox()
        {
            if (!TryParseBoxInput(out var index, out var ip, out var port, out var type, false, out var err))
            { FairyUiHelper.Alert("错误", err); return; }
            if (_boxes.Any(b => b.Index == index)) { FairyUiHelper.Alert("错误", $"编码 {index} 已存在"); return; }
            if (_boxes.Any(b => b.Ip == ip)) { FairyUiHelper.Alert("错误", $"IP {ip} 已存在"); return; }

            var box = new ButtonBoxModel { Index = index, Ip = ip, Port = port, Type = type };
            _boxes.Add(box);
            _selectedBoxIdx = _boxes.Count - 1;
            SaveData();
            _status = "已添加按钮盒";
            _panel?.Repaint();
        }

        private void SaveBox()
        {
            var cur = GetSelectedBox();
            if (cur == null) { FairyUiHelper.Alert("提示", "请先选择按钮盒"); return; }
            if (!TryParseBoxInput(out var index, out var ip, out var port, out var type, true, out var err))
            { FairyUiHelper.Alert("错误", err); return; }
            if (_boxes.Any(b => b.Index == index && b != cur)) { FairyUiHelper.Alert("错误", $"编码 {index} 已存在"); return; }
            if (_boxes.Any(b => b.Ip == ip && b != cur)) { FairyUiHelper.Alert("错误", $"IP {ip} 已存在"); return; }

            cur.Index = index; cur.Ip = ip; cur.Port = port; cur.Type = type;
            SaveData();
            FairyUiHelper.Alert("提示", "保存成功");
            _panel?.Repaint();
        }

        private void ConfirmDeleteBox()
        {
            var cur = GetSelectedBox();
            if (cur == null) { FairyUiHelper.Alert("提示", "请选择要删除的按钮盒"); return; }
            FairyUiHelper.ConfirmThen($"删除编码为 {cur.Index} 的按钮盒？", () =>
            {
                _boxes.Remove(cur);
                _selectedBoxIdx = -1;
                _selectedBtnIdx = -1;
                ClearBoxFields();
                ClearButtonFields();
                SaveData();
                _status = "已删除按钮盒";
                _panel?.Repaint();
            });
        }

        private void AddButton()
        {
            var box = GetSelectedBox();
            if (box == null) { FairyUiHelper.Alert("提示", "请先选择按钮盒"); return; }
            if (!TryParseButtonInput(out var index, out var delay, out var err))
            { FairyUiHelper.Alert("错误", err); return; }
            if (box.Buttons.Any(b => b.Index == index)) { FairyUiHelper.Alert("错误", $"按钮编码 {index} 已存在"); return; }

            box.Buttons.Add(new ButtonModel
            {
                Index = index,
                TriggerMission = _triggerMission.Trim(),
                TriggerMethod = _triggerMethod.Trim(),
                TriggerMethodParams = _triggerParams.Trim(),
                TriggerState = _triggerStateNames[_triggerStateIdx],
                TriggerDelay = delay
            });
            _selectedBtnIdx = box.Buttons.Count - 1;
            SaveData();
            _status = "已添加按钮";
            _panel?.Repaint();
        }

        private void SaveButton()
        {
            var box = GetSelectedBox();
            var btn = GetSelectedButton();
            if (box == null || btn == null) { FairyUiHelper.Alert("提示", "请先选择按钮"); return; }
            if (!TryParseButtonInput(out var index, out var delay, out var err))
            { FairyUiHelper.Alert("错误", err); return; }
            if (box.Buttons.Any(b => b.Index == index && b != btn)) { FairyUiHelper.Alert("错误", $"按钮编码 {index} 已存在"); return; }

            btn.Index = index;
            btn.TriggerMission = _triggerMission.Trim();
            btn.TriggerMethod = _triggerMethod.Trim();
            btn.TriggerMethodParams = _triggerParams.Trim();
            btn.TriggerState = _triggerStateNames[_triggerStateIdx];
            btn.TriggerDelay = delay;
            SaveData();
            FairyUiHelper.Alert("提示", "保存成功");
            _panel?.Repaint();
        }

        private void ConfirmDeleteButton()
        {
            var box = GetSelectedBox();
            var btn = GetSelectedButton();
            if (box == null || btn == null) { FairyUiHelper.Alert("提示", "请选择要删除的按钮"); return; }
            FairyUiHelper.ConfirmThen($"删除编码为 {btn.Index} 的按钮？", () =>
            {
                box.Buttons.Remove(btn);
                _selectedBtnIdx = -1;
                ClearButtonFields();
                SaveData();
                _status = "已删除按钮";
                _panel?.Repaint();
            });
        }

        private bool TryParseBoxInput(out int index, out string ip, out int port, out string type, bool requireSelection, out string err)
        {
            index = 0; ip = ""; port = 502; type = ""; err = "";
            ip = string.IsNullOrWhiteSpace(_boxIp) ? "192.168.1.100" : _boxIp.Trim();
            if (!IsValidIp(ip)) { err = "无效的 IP 地址"; return false; }
            if (!int.TryParse(_boxPort.Trim(), out port)) { err = "端口必须是数字"; return false; }
            if (!int.TryParse(_boxIndex.Trim(), out index))
            {
                index = _boxes.Count > 0 ? _boxes.Max(b => b.Index) + 1 : 1;
                if (!string.IsNullOrWhiteSpace(_boxIndex.Trim())) { err = "编码必须是数字"; return false; }
            }
            type = _typeNames.Length > 0 ? _typeNames[_typeIdx] : "BasicButtonBox";
            if (requireSelection && GetSelectedBox() == null) { err = "请先选择按钮盒"; return false; }
            return true;
        }

        private bool TryParseButtonInput(out int index, out ushort delay, out string err)
        {
            index = 0; delay = 0; err = "";
            var box = GetSelectedBox();
            if (!int.TryParse(_btnIndex.Trim(), out index))
            {
                index = box?.Buttons.Count > 0 ? box.Buttons.Max(b => b.Index) + 1 : 1;
                if (!string.IsNullOrWhiteSpace(_btnIndex.Trim())) { err = "按钮编码必须是数字"; return false; }
            }
            if (!ushort.TryParse(string.IsNullOrWhiteSpace(_triggerDelay) ? "0" : _triggerDelay.Trim(), out delay))
            { err = "触发延迟必须是 0-65535"; return false; }
            return true;
        }

        private bool IsValidIp(string ip)
        {
            if (string.IsNullOrWhiteSpace(ip)) return false;
            var pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
            return Regex.IsMatch(ip, pattern) && IPAddress.TryParse(ip, out var addr)
                && addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork;
        }
    }
}
