using System.Collections.Generic;
using UnityEngine;
using Unity.Services.Core;
using Unity.Services.Authentication;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport.Relay;
using UnityEngine.SceneManagement;
using TMPro;

// --- EXPLICIT REFERENCES ---
// This tells the script exactly which "Lobby" to use
using Unity.Services.Lobby;
using Unity.Services.Lobby.Models;

public class LobbyManager : MonoBehaviour
{
    [Header("UI References")]
    public GameObject lobbyPanel;
    public Transform serverListContent;
    public GameObject serverEntryPrefab;
    public TMP_InputField serverNameInput; 

    public string gameplaySceneName = "mpfreeroam";
    private Lobby joinedLobby; 
    private float heartbeatTimer;
    private float listRefreshTimer;

    private async void Start()
    {
        await UnityServices.InitializeAsync();
        
        if (!AuthenticationService.Instance.IsSignedIn)
        {
            await AuthenticationService.Instance.SignInAnonymouslyAsync();
        }
        Debug.Log("Lobby System Ready.");
    }

    private void Update()
    {
        HandleLobbyHeartbeat();
        HandleLobbyPoll();
    }

    public async void CreatePublicLobby()
    {
        try
        {
            string lobbyName = serverNameInput.text;
            if (string.IsNullOrEmpty(lobbyName)) lobbyName = "Racer " + Random.Range(10, 99);

            // 1. Create Relay
            Allocation allocation = await RelayService.Instance.CreateAllocationAsync(10);
            string relayJoinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);

            // 2. Create Lobby Options
            CreateLobbyOptions options = new CreateLobbyOptions
            {
                IsPrivate = false,
                Data = new Dictionary<string, DataObject>
                {
                    { "RelayCode", new DataObject(DataObject.VisibilityOptions.Member, relayJoinCode) }
                }
            };

            // 3. Create Lobby
            joinedLobby = await LobbyService.Instance.CreateLobbyAsync(lobbyName, 10, options);
            Debug.Log("Lobby Created: " + joinedLobby.Name);

            // 4. Start Host
            RelayServerData relayData = new RelayServerData(allocation, "dtls");
            NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayData);
            NetworkManager.Singleton.StartHost();
            NetworkManager.Singleton.SceneManager.LoadScene(gameplaySceneName, LoadSceneMode.Single);
        }
        catch (System.Exception e)
        {
            Debug.LogError(e.Message);
        }
    }

    public async void RefreshServerList()
    {
        try
        {
            foreach (Transform child in serverListContent) Destroy(child.gameObject);

            // Query Options
            QueryLobbiesOptions options = new QueryLobbiesOptions
            {
                Count = 20,
                Filters = new List<QueryFilter>
                {
                    new QueryFilter(QueryFilter.FieldOptions.AvailableSlots, "0", QueryFilter.OpOptions.GT)
                }
            };

            // Query Lobbies
            QueryResponse response = await LobbyService.Instance.QueryLobbiesAsync(options);

            foreach (Lobby lobby in response.Results)
            {
                GameObject buttonObj = Instantiate(serverEntryPrefab, serverListContent);
                var buttonText = buttonObj.GetComponentInChildren<TextMeshProUGUI>();
                if (buttonText) buttonText.text = $"{lobby.Name} ({lobby.Players.Count}/{lobby.MaxPlayers})";
                
                string id = lobby.Id;
                buttonObj.GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => JoinLobby(id));
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError(e.Message);
        }
    }

    public async void JoinLobby(string lobbyId)
    {
        try
        {
            joinedLobby = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId);
            string relayCode = joinedLobby.Data["RelayCode"].Value;

            JoinAllocation allocation = await RelayService.Instance.JoinAllocationAsync(relayCode);
            RelayServerData relayData = new RelayServerData(allocation, "dtls");
            NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayData);
            NetworkManager.Singleton.StartClient();
        }
        catch (System.Exception e)
        {
            Debug.LogError(e.Message);
        }
    }

    private void HandleLobbyHeartbeat()
    {
        if (joinedLobby != null && IsHost())
        {
            heartbeatTimer -= Time.deltaTime;
            if (heartbeatTimer <= 0f)
            {
                heartbeatTimer = 15f;
                LobbyService.Instance.SendHeartbeatPingAsync(joinedLobby.Id);
            }
        }
    }
    
    private void HandleLobbyPoll()
    {
        if (joinedLobby == null && lobbyPanel.activeSelf)
        {
            listRefreshTimer -= Time.deltaTime;
            if (listRefreshTimer <= 0f)
            {
                listRefreshTimer = 3f;
                RefreshServerList();
            }
        }
    }

    private bool IsHost()
    {
        if (joinedLobby == null) return false;
        return joinedLobby.HostId == AuthenticationService.Instance.PlayerId;
    }
}