using System;
using System.Collections;
using System.Collections.Generic;
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Network;
using Newtonsoft.Json;
using SimpleJSON;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

public sealed class EntryComponent : Entity
{
    public Entry Entry;
}

public class Entry : MonoBehaviour
{
    private static cfg.Tables _tables;
    public static cfg.Tables Tables => _tables;

    private Scene _scene;
    private Session _session;

    public GameObject LoginPanel;
    public GameObject ChatPanel;

    public Text MessageText;
    public InputField PrivateText;
    public InputField UserName;
    public InputField SendMessageText;
    public Button LoginButton;
    public Button ExitButton;
    public Button BroadcastButton;
    public Button ChannelButton;
    public Button PrivateButton;

    public Button SendButton1;
    public Button ChatNodeEventButton;


    void Start()
    {
        LoginPanel.SetActive(true);
        ChatPanel.SetActive(false);
        StartAsync().Coroutine();
        LoginButton.onClick.RemoveAllListeners();
        LoginButton.onClick.AddListener(() => { OnLoginButtonClick().Coroutine(); });
        ExitButton.onClick.RemoveAllListeners();
        ExitButton.onClick.AddListener(() => { OnExitButtonClick().Coroutine(); });
        SendButton1.onClick.RemoveAllListeners();
        SendButton1.onClick.AddListener(() => { OnSendButton1Click().Coroutine(); });
        BroadcastButton.onClick.RemoveAllListeners();
        BroadcastButton.onClick.AddListener(() => { OnBroadcastButtonClick().Coroutine(); });
        ChannelButton.onClick.RemoveAllListeners();
        ChannelButton.onClick.AddListener(() => { OnChannelButtonClick().Coroutine(); });
        PrivateButton.onClick.RemoveAllListeners();
        PrivateButton.onClick.AddListener(() => { OnPrivateButtonClick().Coroutine(); });
    }

    private async FTask StartAsync()
    {
        LoadData();
        // 1. 初始化 Fantasy 框架
        await Fantasy.Platform.Unity.Entry.Initialize();

        // 2. 创建一个 Scene (客户端场景)
        // Scene 是 Fantasy 框架的核心容器,所有功能都在 Scene 下运行
        // SceneRuntimeMode.MainThread 表示在 Unity 主线程运行
        _scene = await Scene.Create(SceneRuntimeMode.MainThread);
        _scene.AddComponent<EntryComponent>().Entry = this;
    }

    private async FTask OnLoginButtonClick()
    {
        // 创建一个连接，这里是连接到目标的Gate服务器
        _session = _scene.Connect(
            "127.0.0.1:20001",
            NetworkProtocolType.KCP,
            () =>
            {
                Log.Debug("连接成功！");
                _session.AddComponent<SessionHeartbeatComponent>().Start(2000);
            },
            () => { Log.Debug("连接失败！"); },
            () => { Log.Debug("断开连接！"); },
            false, 5000);

        // 发送登录的请求给服务器
        var response = (A2C_LoginResponse)await _session.Call(new C2A_LoginRequest()
        {
            Username = UserName.text,
            Password = UserName.text,
            LoginType = 1
        });

        if (response.ErrorCode != 0)
        {
            Log.Error($"登录发生错误{response.ErrorCode}");
            return;
        }
        
        if (!ParseJWT(response.ToKen, out var payload))
        {
            return;
        }
        
        _session = _scene.Connect(
            payload.Address,
            NetworkProtocolType.KCP,
            () =>
            {
                Log.Debug("连接成功！");
                _session.AddComponent<SessionHeartbeatComponent>().Start(2000);
            },
            () => { Log.Debug("连接失败！"); },
            () => { Log.Debug("断开连接！"); },
            false, 5000);

        
        // 发送登录请求到Gate服务器
        var loginResponse = (G2C_LoginResponse)await _session.Call(new C2G_LoginRequest()
        {
            ToKen = response.ToKen
        });
        if (loginResponse.ErrorCode != 0)
        {
            Log.Error($"登录发生错误{loginResponse.ErrorCode}");
            return;
        }
        
        LoginPanel.SetActive(false);
        ChatPanel.SetActive(true);
        Log.Debug("登录成功！");
    }

    private async FTask OnExitButtonClick()
    {
        // var response = (G2C_ExitResponse)await _session.Call(new C2G_ExitRequest());
        // if (response.ErrorCode != 0)
        // {
        //     Log.Error($"退出游戏错误 ErrorCode:{response.ErrorCode}");
        //     return;
        // }
        // LoginPanel.SetActive(true);
        // ChatPanel.SetActive(false);
        // Log.Debug("退出游戏成功！");
    }

    private async FTask OnSendButton1Click()
    {
        await FTask.CompletedTask;
        // SendButton1.interactable = false;
        // var response = (Chat2C_SendMessageResponse) await _session.Call(new C2Chat_SendMessageRequest());
        // if (response.ErrorCode != 0)
        // {
        //     Log.Error($"发送聊天消息失败 ErrorCode:{response.ErrorCode}");
        //     return;
        // }
        // Log.Debug("发送聊天消息成功！");
        // SendButton1.interactable = true;
    }

    private async FTask OnBroadcastButtonClick()
    {
        BroadcastButton.interactable = false;
        var tree = ChatTreeFactory.Broadcast(_scene);
        tree = tree.AddendPositionNode(SendMessageText.text, "勇者大陆", 121, 131, 111);

        var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest()
        {
            ChatInfoTree = tree
        });
        if (response.ErrorCode != 0)
        {
            Log.Error($"发送聊天消息失败 ErrorCode:{response.ErrorCode}");
        }

        BroadcastButton.interactable = true;
    }

    private async FTask OnChannelButtonClick()
    {
        ChannelButton.interactable = false;
        var tree = ChatTreeFactory.Team(_scene);
        tree.ChatChannelId = 1;
        // tree = tree.AddendTextNode("你好，欢迎来到Fantasy Chat！").AddendLinkNode("点击这里http://www.fantasy.com.cn");
        var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest()
        {
            ChatInfoTree = tree
        });
        if (response.ErrorCode != 0)
        {
            Log.Error($"发送频道聊天消息失败 ErrorCode:{response.ErrorCode}");
        }

        ChannelButton.interactable = true;
    }

    private async FTask OnPrivateButtonClick()
    {
        PrivateButton.interactable = false;
        var tree = ChatTreeFactory.Private(_scene);
        tree.Target.Add(Convert.ToInt64(PrivateText.text));
        // tree = tree.AddendTextNode("你好，欢迎来到Fantasy Chat！").AddendLinkNode("点击这里http://www.fantasy.com.cn");

        var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest()
        {
            ChatInfoTree = tree
        });
        if (response.ErrorCode != 0)
        {
            Log.Error($"发送私聊消息失败 ErrorCode:{response.ErrorCode}");
        }

        PrivateButton.interactable = true;
    }


    #region Config

    private void LoadData()
    {
        // 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
        _tables = new cfg.Tables(LoadJson);
    }

    private static JSONNode LoadJson(string file)
    {
        //var json = File.ReadAllText($"{your_json_dir}/{file}.json", System.Text.Encoding.UTF8);
        //Assets/ResRaw/config/tb/tbbait.json
        var jsonAsset = AssetDatabase.LoadAssetAtPath<TextAsset>($"Assets/ResRaw/config/tb/{file}.json");
        return JSON.Parse(jsonAsset.text);
    }

    #endregion

    #region JWT

    public bool ParseJWT(string toKen, out Payload payloadData)
    {
        payloadData = null;

        try
        {
            // JWT通常是由三个部分组成的,Header,Payload,Signature。
            var tokens = toKen.Split('.');

            if (tokens.Length != 3)
            {
                Log.Error("Invalid JWT token");
                return false;
            }

            // JWT的Payload不是标准的Base64格式，因为咱们C#的Convert要求是一个标准的Base64格式。
            // JWT的Payload是Base64URL格式,它里面的"-"替代成了"+","_"替代成了"/",需要把这些给还原成Base64格式
            var basePayload = tokens[1].Replace('-', '+').Replace('_', '/');
            // 因为Base64的编码长度需要是4的倍数，如果不是的话咱们需要把这个长度用=来填充，使其长度符合要求
            switch (basePayload.Length % 4)
            {
                // case 0:
                // {
                //     // 如果这个余数是0，那就表示长度已经是4的倍数，那就没必要处理了。
                //     break;
                // }
                // case 1:
                // {
                //     // 如果这个余数是1，那就表示这个Base64格式是不正确的，不是咱们发放的token。
                //     // 这样情况下，也不需要处理了。
                //     break;
                // }
                case 2:
                {
                    basePayload += "==";
                    break;
                }
                case 3:
                {
                    basePayload += "=";
                    break;
                }
            }

            // 将修复后的字符串解码为数组
            var basePayloadBytes = Convert.FromBase64String(basePayload);
            var payload = System.Text.Encoding.UTF8.GetString(basePayloadBytes);
            payloadData =
                JsonConvert.DeserializeObject<Payload>(payload); //JsonHelper.Deserialize<Payload>(payload);
            return true;
        }
        catch (Exception e)
        {
            Log.Error(e);
            return false;
        }
    }

    #endregion
}

public sealed class Payload
{
    public long aId { get; set; }
    public string Address { get; set; }
    public uint SceneId { get; set; }
    public int exp { get; set; }
    public string iss { get; set; }
    public string aud { get; set; }
}