using System.Globalization;
using System.Reflection;
using System.Text.Json;
using NBC;
using NBC.InnerMessage;
using NBC.Network;
using NBC.Network.Interface;
using ProtoBuf;
using EventArgs = System.EventArgs;

#pragma warning disable CS8618 // 在退出构造函数时，不可为 null 的字段必须包含非 null 值。请考虑添加 'required' 修饰符或声明为可以为 null。

namespace FantasyNetTest;

public partial class Form1 : Form
{
    private Config _config;

    private ScriptLoader _scriptLoader;

    private List<Type> _allRequest = new List<Type>();

    private object _selectProtocolObject;
    private TableLayoutPanel _tableLayoutPanel;

    private Scene _scene;

    private string _nowAccount;

    public Form1()
    {
        InitializeComponent();
        this.FormBorderStyle = FormBorderStyle.FixedSingle;
        this.MaximizeBox = false;
        this.MinimizeBox = false;

        comboBoxProtocol.SelectedIndexChanged += ComboBox_SelectedIndexChanged;
        comboBoxProtocol.DropDownStyle = ComboBoxStyle.DropDownList;
        _config ??= new Config();
        LoadConfig();

        if (_config.Accounts.Count > 0)
        {
            comboBoxAccount.Text = _config.Accounts.First();
        }

        _scriptLoader = new ScriptLoader();


        var time = UnityEngine.Time.time;
        Log.Init(logTextBox);
        LoadProtocol();
        StartAsync().Coroutine();
    }

    private void SwitchLoginButtonState()
    {
        if (_session == null)
        {
            buttonConnect.Text = "登录";
        }
        else
        {
            buttonConnect.Text = "退出";
        }
    }

    #region 框架

    private NBC.Platform.Unity.Entry _entry;

    private async FTask StartAsync()
    {
        Log.Info("开始初始化框架");
        // 初始化框架
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        List<Assembly> loadAssemblies = new List<Assembly>();
        foreach (var assembly in assemblies)
        {
            // 跳过系统程序集以提高性能（可选）
            if (IsSystemAssembly(assembly))
                continue;
            loadAssemblies.Add(assembly);
        }

        _entry = await NBC.Platform.Unity.Entry.Initialize(loadAssemblies.ToArray());
        _scene = await Scene.Create(SceneRuntimeMode.MainThread);
        _scene.AddComponent<JWTParseComponent>();

        NetMessageDelegate.OnMessage += OnMessage;
        NetMessageDelegate.OnRequest += OnRequest;
        NetMessageDelegate.OnResponse += OnResponse;
        Log.Succeed("初始化框架成功");
    }

    // 判断是否是系统程序集（可选优化）
    private static bool IsSystemAssembly(System.Reflection.Assembly assembly)
    {
        string assemblyName = assembly.FullName;
        return assemblyName.StartsWith("System") ||
               assemblyName.StartsWith("Microsoft.") ||
               assemblyName.StartsWith("UnityEngine") ||
               assemblyName.StartsWith("UnityEditor") ||
               assemblyName.StartsWith("mscorlib") ||
               assemblyName.StartsWith("netstandard") ||
               assemblyName.StartsWith("nunit.") ||
               assemblyName.StartsWith("Unity.");
    }

    private void OnMessage(Session session, Type type, object message, uint rpcId, uint protocolCode)
    {
        if (session != _session) return;
        var json = message.ToJson();
        Log.Succeed($"收到消息, type={type.Name} data={json}");
    }

    private void OnRequest(IRequest request, long routeId = 0)
    {
        if (request == null) return;
        if (request is PingRequest) return;
        var json = request.ToJson();
        Log.Info($"发送消息, op={request.OpCode()} data={json}");
    }

    private void OnResponse(IResponse request)
    {
        if (request == null) return;
        if (request is PingResponse) return;
        var json = request.ToJson();
        Log.Succeed($"收到响应消息, op={request.OpCode()} data={json}");
    }

    #endregion

    #region 登录

    private Session? _session;

    private async FTask OnLoginButtonClick(string account)
    {
        // 根据用户名来选择目标的鉴权服务器
        // 根据鉴权服务器地址来创建一个新的网络会话
        _session = SessionHelper.CreateSession(_scene, _config.Server, OnConnectComplete,
            OnConnectFail,
            OnConnectDisconnect);

        var acc = account;


        // 首先确保已加载包含该类的程序集
        var type = CoderLoader.GetTypeByName("C2A_LoginRequest");


        if (type == null)
        {
            Log.Error("NBC.C2A_LoginRequest 类未加载");
            return;
        }

        var instance = Activator.CreateInstance(type);

        if (instance == null)
        {
            Log.Error("NBC.C2A_LoginRequest 类实例化失败");
            return;
        }

        instance.SetPropertyValue("Username", acc);
        instance.SetPropertyValue("Password", acc);
        instance.SetPropertyValue("LoginType", 1);

        if (instance is not IRequest loginRequest)
        {
            Log.Error("instance is not IRequest loginRequest");
            return;
        }

        var response = await _session.Call(loginRequest);
        if (response.ErrorCode != 0)
        {
            Log.Error($"登录发生错误{response.ErrorCode}");
            return;
        }

        string? token = response.GetPropertyValue("ToKen")?.ToString();

        if (string.IsNullOrEmpty(token))
        {
            Log.Error($"登录 Token is null");
            return;
        }

        if (!_scene.GetComponent<JWTParseComponent>().Parse(token, out var payload))
        {
            return;
        }

        // 根据ToKen返回的Address登录到Gate服务器
        _session = SessionHelper.CreateSession(_scene, payload.Address, OnConnectComplete, OnConnectFail,
            OnConnectDisconnect);


        // 首先确保已加载包含该类的程序集
        var typeGate = CoderLoader.GetTypeByName("C2G_LoginRequest");


        if (typeGate == null)
        {
            Log.Error("NBC.C2G_LoginRequest 类未加载");
            return;
        }

        var instanceGate = Activator.CreateInstance(typeGate);

        if (instanceGate == null)
        {
            Log.Error("NBC.C2G_LoginRequest 类实例化失败");
            return;
        }

        instanceGate.SetPropertyValue("ToKen", token);
        if (instanceGate is not IRequest loginGateRequest)
        {
            Log.Error("instance is not IRequest loginRequest");
            return;
        }

        var responseGate = await _session.Call(loginGateRequest);
        if (responseGate.ErrorCode != 0)
        {
            Log.Error($"登录网关发生错误{responseGate.ErrorCode}");
            return;
        }

        Log.Succeed($"登录到Gate服务器成功！ErrorCode:{responseGate.ErrorCode}");


        // // 发送登录的请求给服务器
        // var response = (A2C_LoginResponse)await _session.Call(new C2A_LoginRequest()
        // {
        //     Username = acc,
        //     Password = acc,
        //     LoginType = 1
        // });
        //
        // if (response.ErrorCode != 0)
        // {
        //     Log.Error($"登录发生错误{response.ErrorCode}");
        //     return;
        // }
        //
        // if (!_scene.GetComponent<JWTParseComponent>().Parse(response.ToKen, out var payload))
        // {
        //     return;
        // }
        //
        // // 根据ToKen返回的Address登录到Gate服务器
        // _session = SessionHelper.CreateSession(_scene, payload.Address, OnConnectComplete, OnConnectFail,
        //     OnConnectDisconnect);
        // // 发送登录请求到Gate服务器
        // var loginResponse = (G2C_LoginResponse)await _session.Call(new C2G_LoginRequest()
        // {
        //     ToKen = response.ToKen
        // });
        // if (loginResponse.ErrorCode != 0)
        // {
        //     Log.Error($"登录发生错误{loginResponse.ErrorCode}");
        //     return;
        // }
        //
        // Log.Succeed($"登录到Gate服务器成功！ErrorCode:{loginResponse.ErrorCode}");
        SwitchLoginButtonState();
    }

    private void OnConnectComplete()
    {
        Log.Succeed("连接成功");
        // 添加心跳组件给Session。
        // Start(2000)就是2000毫秒。
        _session?.AddComponent<SessionHeartbeatComponent>().Start(5000);
    }

    private void OnConnectFail()
    {
        Log.Error("连接失败");
        _session = null;
        SwitchLoginButtonState();
    }

    private void OnConnectDisconnect()
    {
        Log.Error("连接断开");
        _session = null;
        SwitchLoginButtonState();
    }

    #endregion

    #region Config

    private void LoadConfig()
    {
        var configPath = Path.Combine(Application.StartupPath, "Config.json");
        if (File.Exists(configPath))
        {
            string jsonContent = File.ReadAllText(configPath);
            var cfg = JsonSerializer.Deserialize<Config>(jsonContent);
            if (cfg != null)
            {
                _config.Server = cfg.Server;
                _config.Heartbeat = cfg.Heartbeat;
                _config.ProtocolScriptPath = cfg.ProtocolScriptPath;
            }
        }
    }

    private void SaveConfig()
    {
        var account = comboBoxAccount.Text;
        _config.Accounts.Add(account);
        var configPath = Path.Combine(Application.StartupPath, "Config.json");
        var json = JsonSerializer.Serialize(_config);
        File.WriteAllText(configPath, json);
    }

    #endregion

    #region 协议下拉框

    private void LoadProtocol()
    {
        Log.Info("开始加载协议");
        _scriptLoader.LoadAndExecuteScripts(_config.ProtocolScriptPath);
        Log.Succeed("加载协议完成");
        CoderLoader.Load();
        SetProtocolComboBox();
    }

    private void SetProtocolComboBox()
    {
        comboBoxProtocol.Items.Clear();

        var types = CoderLoader.RequestTypes;
        _allRequest.Clear();
        _allRequest.AddRange(types);
        foreach (var type in _allRequest)
        {
            comboBoxProtocol.Items.Add(type.Name);
        }
    }

    // 事件处理方法
    private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        ComboBox comboBox = (ComboBox)sender;

        var index = comboBox.SelectedIndex;
        var proto = comboBox.SelectedItem?.ToString();
        SelectedProtocol(_allRequest[index]);
    }

    private void SelectedProtocol(Type type)
    {
        var obj = Activator.CreateInstance(type);
        if (obj != null)
        {
            _selectProtocolObject = obj;
            LoadCacheProtocol(obj);
            // 生成UI
            GenerateKeyValueInputs(panel1, _selectProtocolObject);
        }
    }

    #endregion

    #region 协议内容反射

    private List<PropertyInfo> _propertyInfos = new List<PropertyInfo>();

    public void GenerateKeyValueInputs(Panel containerPanel, object configObject)
    {
        // 清除现有控件
        containerPanel.Controls.Clear();

        // 创建TableLayoutPanel
        var tablePanel = new TableLayoutPanel
        {
            ColumnCount = 2,
            Dock = DockStyle.Top, // 重要：设置为Top而不是Fill
            AutoSize = true,
            AutoSizeMode = AutoSizeMode.GrowAndShrink,
            GrowStyle = TableLayoutPanelGrowStyle.AddRows
        };

        _tableLayoutPanel = tablePanel;

        // 设置列宽比例
        tablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30));
        tablePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 70));

        // 获取对象的所有属性
        var propertySources = configObject.GetType().GetProperties();

        _propertyInfos.Clear();

        foreach (var propertySource in propertySources)
        {
            if (propertySource.GetCustomAttribute<ProtoMemberAttribute>() != null)
            {
                _propertyInfos.Add(propertySource);
            }
        }

        PropertyInfo[] properties = _propertyInfos.ToArray();

        //var properties
        // 设置表格行数和列数
        tablePanel.ColumnCount = 2;
        tablePanel.RowCount = properties.Length;

        // 设置固定的行高
        int rowHeight = 30; // 每行固定高度

        // 添加属性和值输入框
        for (int i = 0; i < properties.Length; i++)
        {
            var property = properties[i];

            // 设置行样式
            tablePanel.RowStyles.Add(new RowStyle(SizeType.Absolute, rowHeight));

            // 添加属性名标签 (Key)
            var label = new Label
            {
                Text = $@"[{GetTypeShowName(property.PropertyType)}] {property.Name}",
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.MiddleLeft,
                Margin = new Padding(3),
                Height = rowHeight,
            };
            if (label.Text.Length > 13)
            {
                label.Text = label.Text.Substring(0, 12);
            }

            tablePanel.Controls.Add(label, 0, i);

            tablePanel.Controls.Add(CreateControl(property, configObject), 1, i);
        }

        // 将TableLayoutPanel添加到容器Panel中
        containerPanel.Controls.Add(tablePanel);

        // 启用自动滚动
        containerPanel.AutoScroll = true;
        containerPanel.VerticalScroll.Enabled = true;
        containerPanel.VerticalScroll.Visible = true;
    }

    private Control CreateControl(PropertyInfo property, object configObject)
    {
        // 添加值输入控件 (Value)
        Control inputControl;

        // 根据属性类型创建不同的输入控件
        if (property.PropertyType == typeof(bool))
        {
            var checkbox = new CheckBox
            {
                Checked = (bool)property.GetValue(configObject),
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.MiddleLeft
            };
            inputControl = checkbox;
        }
        else if (property.PropertyType == typeof(int) || property.PropertyType == typeof(long) ||
                 property.PropertyType == typeof(double) ||
                 property.PropertyType == typeof(decimal) || property.PropertyType == typeof(float))
        {
            var numericBox = new NumericUpDown
            {
                Value = Convert.ToDecimal(property.GetValue(configObject)),
                Dock = DockStyle.Fill,
                Minimum = decimal.MinValue,
                Maximum = decimal.MaxValue
            };
            inputControl = numericBox;
        }
        else if (property.PropertyType == typeof(uint))
        {
            var numericBox = new NumericUpDown
            {
                Value = Convert.ToDecimal(property.GetValue(configObject)),
                Dock = DockStyle.Fill,
                Minimum = uint.MinValue,
                Maximum = uint.MaxValue
            };
            inputControl = numericBox;
        }
        else if (property.PropertyType == typeof(short))
        {
            var numericBox = new NumericUpDown
            {
                Value = Convert.ToDecimal(property.GetValue(configObject)),
                Dock = DockStyle.Fill,
                Minimum = short.MinValue,
                Maximum = short.MaxValue
            };
            inputControl = numericBox;
        }
        else
        {
            var textBox = new TextBox
            {
                Text = property.GetValue(configObject)?.ToString() ?? "",
                Dock = DockStyle.Fill,
                Margin = new Padding(3)
            };
            inputControl = textBox;
        }

        return inputControl;
    }

    private string GetTypeShowName(Type type)
    {
        if (type == typeof(bool))
        {
            return "B";
        }

        if (type == typeof(byte))
        {
            return "B";
        }

        if (type == typeof(short))
        {
            return "S";
        }

        if (type == typeof(int))
        {
            return "I";
        }

        if (type == typeof(uint))
        {
            return "U";
        }

        if (type == typeof(long))
        {
            return "L";
        }

        if (type == typeof(double))
        {
            return "D";
        }

        if (type == typeof(float))
        {
            return "F";
        }

        if (type == typeof(decimal))
        {
            return "M";
        }

        if (type == typeof(string))
        {
            return "S";
        }

        return type.Name;
    }

    public void SaveDataFromUI(object configObject)
    {
        TableLayoutPanel tablePanel = _tableLayoutPanel;

        // var properties = configObject.GetType().GetProperties();

        for (int i = 0; i < _propertyInfos.Count; i++)
        {
            var property = _propertyInfos[i];
            var inputControl = tablePanel.GetControlFromPosition(1, i);

            try
            {
                if (inputControl is CheckBox checkbox)
                {
                    property.SetValue(configObject, checkbox.Checked);
                }
                else if (inputControl is NumericUpDown numericBox)
                {
                    if (property.PropertyType == typeof(int))
                        property.SetValue(configObject, (int)numericBox.Value);
                    else if (property.PropertyType == typeof(double))
                        property.SetValue(configObject, (double)numericBox.Value);
                    else if (property.PropertyType == typeof(decimal))
                        property.SetValue(configObject, numericBox.Value);
                    else if (property.PropertyType == typeof(uint))
                        property.SetValue(configObject, (uint)numericBox.Value);
                    else if (property.PropertyType == typeof(float))
                        property.SetValue(configObject, (float)numericBox.Value);
                    else if (property.PropertyType == typeof(short))
                        property.SetValue(configObject, (short)numericBox.Value);
                }
                else if (inputControl is TextBox textBox)
                {
                    property.SetValue(configObject, Convert.ChangeType(textBox.Text, property.PropertyType));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"设置属性 {property.Name} 时出错: {ex.Message}");
            }
        }
    }

    #endregion

    #region 协议内存缓存和加载

    private string ProtocolPathPath => string.IsNullOrEmpty(_nowAccount)
        ? Path.Combine(Application.StartupPath, "Protocol")
        : Path.Combine(Application.StartupPath, _nowAccount, "Protocol");

    private void CacheProtocol(object obj)
    {
        if (obj == null) return;
        if (!Directory.Exists(ProtocolPathPath))
        {
            Directory.CreateDirectory(ProtocolPathPath);
        }

        var json = JsonSerializer.Serialize(obj);
        var type = obj.GetType();
        File.WriteAllText(Path.Combine(ProtocolPathPath, type.Name), json);
    }

    private void LoadCacheProtocol(object obj)
    {
        if (obj == null) return;
        if (!Directory.Exists(ProtocolPathPath))
        {
            return;
        }

        var path = Path.Combine(ProtocolPathPath, obj.GetType().Name);
        if (File.Exists(path))
        {
            var json = File.ReadAllText(path);
            var deserializeObj = JsonSerializer.Deserialize(json, obj.GetType());
            if (deserializeObj != null)
            {
                // 获取所有可写属性
                var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(p => p.CanWrite);

                foreach (var property in properties)
                {
                    // 从反序列化对象中获取值
                    var value = property.GetValue(deserializeObj);
                    // 设置到目标对象中
                    property.SetValue(obj, value);
                }

                // 或者处理字段（如果需要）
                var fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
                    .Where(f => !f.IsInitOnly); // 排除只读字段

                foreach (var field in fields)
                {
                    var value = field.GetValue(deserializeObj);
                    field.SetValue(obj, value);
                }
            }
        }
    }

    #endregion

    #region 事件

    private void buttonSend_Click(object sender, EventArgs e)
    {
        if (_session == null)
        {
            Log.Error("未连接服务器！");
            return;
        }

        if (_selectProtocolObject == null)
        {
            Log.Error("未选择协议！");
            return;
        }

        SaveDataFromUI(_selectProtocolObject);
        CacheProtocol(_selectProtocolObject);

        if (_selectProtocolObject is IRequest request)
        {
            _session.Call(request).Coroutine();
        }
    }

    private void buttonConnect_Click(object sender, EventArgs e)
    {
        _nowAccount = comboBoxAccount.Text;
        if (_session == null)
        {
            if (string.IsNullOrEmpty(comboBoxAccount.Text))
            {
                Log.Error("未输入账号");
                return;
            }

            //登录
            OnLoginButtonClick(comboBoxAccount.Text).Coroutine();
            SwitchLoginButtonState();
        }
        else
        {
            //退出
            _session.Dispose();
        }

        SaveConfig();
    }


    private void timer1_Tick(object sender, EventArgs e)
    {
        Log.Tick();
    }

    private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
    {
        Log.Clear();
    }

    private void timer2_Tick(object sender, EventArgs e)
    {
        _entry?.Update();
        if (_session != null && _session.IsDisposed)
        {
            _session.Dispose();
            _session = null;
            return;
        }
    }

    private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
    {
        Log.Info("重新加载协议");
    }

    #endregion
}