using Rokid.MRC;
using System;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

//客户端玩家数据管理，不允许一个客户端登录两次，用于后续公司账号
public class PlayerManager
{
    PlayerManager()
    {
        PlayerDataDic = new Dictionary<string, PlayerData>();
        m_ClientIDToPlayerId = new Dictionary<ulong, string>();
    }

    public static PlayerManager Instance => s_Instance ??= new PlayerManager();
    static PlayerManager s_Instance;

    //PlayerID——SessionPlayerData
    public Dictionary<string, PlayerData> PlayerDataDic;

    //ClientId——PlayerID
    private Dictionary<ulong, string> m_ClientIDToPlayerId;

    private bool m_HasSessionStarted;

    //客户端断开连接
    public void DisconnectClient(ulong clientId)
    {
        if(m_HasSessionStarted)
        {
            //将客户端标记为断线，但是不移除数据。便于后续重连
            if(m_ClientIDToPlayerId.TryGetValue(clientId, out var playerId))
            {
                if(GetPlayerData(playerId)?.ClientId == clientId)
                {
                    var clientData = PlayerDataDic[playerId];
                    clientData.IsConnected = false;
                    PlayerDataDic[playerId] = clientData;
                }
            }
        }
        else
        {
            //未初始化管理器。移除数据（无需保存数据）
            if(m_ClientIDToPlayerId.TryGetValue(clientId, out var playerId))
            {
                m_ClientIDToPlayerId.Remove(clientId);
                PlayerData data = GetPlayerData(playerId);

                if(data != null)
                {
                    if(data.IsVideoClient)
                    {
                        CameraController.Instance.ShutDownComposition();
                    }

                    if(data.ClientId == clientId)
                    {
                        PlayerDataDic.Remove(playerId);
                    }
                }
            }
        }
    }

    //该客户端是否已连接
    public bool IsDuplicateConnection(string playerId)
    {
        return PlayerDataDic.ContainsKey(playerId) && PlayerDataDic[playerId].IsConnected;
    }

    //关键方法，当客户端连接（重连）到服务端，则保存（更新）客户端数据。playerId是客户端生成并发送到服务端的Guid
    public void SetupConnectingPlayerSessionData(ulong clientId, string playerId, PlayerData sessionPlayerData)
    {
        var isReconnecting = false;

        //判断是否同一客户端
        if(IsDuplicateConnection(playerId))
        {
            Debug.LogError($"Player ID {playerId} already exists. This is a duplicate connection. Rejecting this session data.");
            return;
        }

        //判断是否重连
        if(PlayerDataDic.ContainsKey(playerId))
        {
            if(!PlayerDataDic[playerId].IsConnected)
            {
                isReconnecting = true;
            }
        }

        //重连，则更新客户端数据
        if(isReconnecting)
        {
            sessionPlayerData = PlayerDataDic[playerId];
            sessionPlayerData.ClientId = clientId;
            sessionPlayerData.IsConnected = true;
        }

        //缓存数据
        m_ClientIDToPlayerId[clientId] = playerId;
        PlayerDataDic[playerId] = sessionPlayerData;
    }

    //根据ClientId，获取PlayerId
    public string GetPlayerId(ulong clientId)
    {
        if(m_ClientIDToPlayerId.TryGetValue(clientId, out string playerId))
        {
            return playerId;
        }

        Debug.Log($"No client player ID found mapped to the given client ID: {clientId}");
        return null;
    }

    //根据ClientId获取客户端数据SessionPlayerData
    public PlayerData GetPlayerData(ulong clientId)
    {
        var playerId = GetPlayerId(clientId);
        if(playerId != null)
        {
            return GetPlayerData(playerId);
        }

        Debug.Log($"No client player ID found mapped to the given client ID: {clientId}");
        return null;
    }

    public PlayerData GetPlayerData(string playerId)
    {
        if(PlayerDataDic.TryGetValue(playerId, out PlayerData data))
        {
            return data;
        }

        Debug.Log($"No PlayerData of matching player ID found: {playerId}");
        return null;
    }

    public PlayerData GetConnectedPlayerData()
    {
        foreach(var playerData in PlayerDataDic.Values)
        {
            if(playerData.IsConnected && playerData.ClientId != NetworkManager.Singleton.LocalClientId)
            {
                return playerData;
            }
        }

        return null;
    }

    //更新某个ClientId的客户端数据SessionPlayerData
    public void SetPlayerData(ulong clientId, PlayerData sessionPlayerData)
    {
        if(m_ClientIDToPlayerId.TryGetValue(clientId, out string playerId))
        {
            PlayerDataDic[playerId] = sessionPlayerData;
        }
        else
        {
            Debug.LogError($"No client player ID found mapped to the given client ID: {clientId}");
        }
    }

    //断开所有客户端
    public void CloseAllClient()
    {
        foreach(var playerData in PlayerDataDic.Values)
        {
            NetworkManager.Singleton?.DisconnectClient(playerData.ClientId);
        }

        OnServerEnded();
    }

    //标记管理器已经启动。可以缓存已断开连接的客户端数据
    public void OnSessionStarted()
    {
        m_HasSessionStarted = true;
    }
    
    //重新初始化已连接的客户端。清空所有断开的客户端数据（下次连上，则标识为新客户端）
    public void OnSessionEnded()
    {
        ClearDisconnectedPlayersData();
        ReinitializePlayersData();
        m_HasSessionStarted = false;
    }

    //服务端关闭，清空所有数据
    public void OnServerEnded()
    {
        PlayerDataDic.Clear();
        m_ClientIDToPlayerId.Clear();
        m_HasSessionStarted = false;
    }

    //重新初始化已连接的客户端。调用每个客户端的SessionPlayerData.Reinitialize方法
    void ReinitializePlayersData()
    {
        foreach(var id in m_ClientIDToPlayerId.Keys)
        {
            string playerId = m_ClientIDToPlayerId[id];
            PlayerData sessionPlayerData = PlayerDataDic[playerId];
            sessionPlayerData.Reinitialize();
            PlayerDataDic[playerId] = sessionPlayerData;
        }
    }

    //清空所有断开的客户端数据
    void ClearDisconnectedPlayersData()
    {
        //收集所有断开连接的客户端
        List<ulong> idsToClear = new List<ulong>();
        foreach(var id in m_ClientIDToPlayerId.Keys)
        {
            var data = GetPlayerData(id);
            if(data is { IsConnected: false })
            {
                idsToClear.Add(id);
            }
        }

        //移除数据
        foreach(var id in idsToClear)
        {
            string playerId = m_ClientIDToPlayerId[id];
            if(GetPlayerData(playerId)?.ClientId == id)
            {
                PlayerDataDic.Remove(playerId);
            }

            m_ClientIDToPlayerId.Remove(id);
        }
    }

    public bool HaveAnchorPlayer()
    {
        foreach(var client in PlayerDataDic)
        {
            PlayerData playerData = client.Value;
            if(playerData.IsConnected && playerData.Anchor != null)
            {
                return true;
            }
        }

        return false;
    }

    public bool HaveVideoPlayer()
    {
        foreach(var client in PlayerDataDic)
        {
            PlayerData playerData = client.Value;
            if(playerData.IsConnected && playerData.IsVideoClient)
            {
                return true;
            }
        }

        return false;
    }

    public PlayerData GetVideoPlayer()
    {
        foreach(var client in PlayerDataDic)
        {
            PlayerData playerData = client.Value;
            if(playerData.IsConnected && playerData.IsVideoClient)
            {
                return playerData;
            }
        }

        return null;
    }

    public bool HavePlayer()
    {
        foreach(var client in PlayerDataDic)
        {
            PlayerData playerData = client.Value;
            if(playerData.IsConnected && playerData.ClientId != 0)
            {
                return true;
            }
        }

        return false;
    }
}
