using Game.Model;
using GameServices;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using UnityEngine;
using UnityEngine.SceneManagement;
using Steamworks;
using System;
using System.Threading.Tasks;

public class ClientNetworkManager : NetworkManager
{
    [SerializeField] private string mainMenuSceneName = "MainMenu";
    

    [SerializeField] private string defaultServerIP = "owo";
    [SerializeField] private ushort defaultServerPort = 7777;
    

    private bool isConnecting = false;
    private CSteamID targetSteamID;
    
  
    private Callback<P2PSessionRequest_t> p2pSessionRequestCallback;
    private bool usingSteamNetworking = false;
    
    async void Start()
    {
     
        if (SteamAPI.IsSteamRunning())
        {
            p2pSessionRequestCallback = Callback<P2PSessionRequest_t>.Create(OnP2PSessionRequest);
            await ProcessSteamPlayerInfo();
        }
        else
        {
            Debug.LogWarning("Steam is not running. Using PlayerPrefs data if available.");
            ProcessPlayerPrefs();
        }
        
   
        LoadMainMenu();
        
        Debug.Log("Client Ready");
    }
    
    private void OnP2PSessionRequest(P2PSessionRequest_t request)
    {
       
        Debug.Log($"Accepting P2P session with: {request.m_steamIDRemote}");
        SteamNetworking.AcceptP2PSessionWithUser(request.m_steamIDRemote);
    }
    
    public bool ConnectToServerViaSteam(string steamIdString)
    {
        if (isConnecting || IsClient)
        {
            Debug.LogWarning("Already connecting or connected to server");
            return false;
        }
        
        if (!SteamAPI.IsSteamRunning())
        {
            Debug.LogError("Steam is not running. Cannot connect via Steam.");
            return false;
        }
        
    
        ulong steamIdValue;
        if (!ulong.TryParse(steamIdString, out steamIdValue))
        {
            Debug.LogError($"Invalid Steam ID format: {steamIdString}");
            return false;
        }
        
        CSteamID serverId = new CSteamID(steamIdValue);
        return ConnectToServerViaSteam(serverId);
    }
    
    public bool ConnectToServerViaSteam(CSteamID serverId)
    {
        if (isConnecting || IsClient)
        {
            Debug.LogWarning("Already connecting or connected to server");
            return false;
        }
        
        if (!SteamAPI.IsSteamRunning())
        {
            Debug.LogError("Steam is not running. Cannot connect via Steam.");
            return false;
        }
        
        Debug.Log($"Connecting to Steam server ID: {serverId}");
        
   
        targetSteamID = serverId;
        
      
        SteamNetworking.AllowP2PPacketRelay(true);
        
       
        byte[] connectData = System.Text.Encoding.UTF8.GetBytes("CONNECT_REQUEST");
        bool success = SteamNetworking.SendP2PPacket(
            serverId, 
            connectData, 
            (uint)connectData.Length, 
            EP2PSend.k_EP2PSendReliable);
        
        if (success)
        {
            Debug.Log("Initial Steam P2P connection packet sent");
            isConnecting = true;
            usingSteamNetworking = true;
            
      
            SetupNetcodeForSteamConnection(serverId);
            
            return true;
        }
        else
        {
            Debug.LogError("Failed to send initial Steam P2P connection packet");
            return false;
        }
    }
    
    private void SetupNetcodeForSteamConnection(CSteamID serverId)
    {

        UnityTransport existingTransport = GetComponent<UnityTransport>();
        if (existingTransport != null)
        {
            DestroyImmediate(existingTransport);
        }
        
        // Add fresh transport
        UnityTransport transport = gameObject.AddComponent<UnityTransport>();
        

        transport.ConnectionData.Address = "127.0.0.1"; 
        transport.ConnectionData.Port = defaultServerPort;
        transport.MaxConnectAttempts = 3;
        transport.ConnectTimeoutMS = 15000;
        
        NetworkConfig.NetworkTransport = transport;
        
        // Attach connection callbacks
        OnClientConnectedCallback += OnClientConnected;
        OnClientDisconnectCallback += OnClientDisconnect;
        
        // Start client
        bool result = StartClient();
        
        if (!result)
        {
            Debug.LogError("Failed to start client connection");
            isConnecting = false;
            usingSteamNetworking = false;
        }
    }

    public bool ConnectToServer(string serverIP = null, ushort? serverPort = null)
    {
        if (isConnecting || IsClient)
        {
            Debug.LogWarning("Already connecting or connected to server");
            return false;
        }
        
        string targetIP = serverIP ?? defaultServerIP;
        ushort targetPort = serverPort ?? defaultServerPort;
        

        UnityTransport existingTransport = GetComponent<UnityTransport>();
        if (existingTransport != null)
        {
            DestroyImmediate(existingTransport);
        }
        
     
        UnityTransport transport = gameObject.AddComponent<UnityTransport>();
        
       
        transport.ConnectionData.Address = targetIP;
        transport.ConnectionData.Port = targetPort;
        
     
        transport.MaxConnectAttempts = 2;
        transport.ConnectTimeoutMS = 10000;
        
        NetworkConfig.NetworkTransport = transport;
        
        Debug.Log($"Attempting to connect to server at {targetIP}:{targetPort}");
        
        isConnecting = true;
        usingSteamNetworking = false;
        
       
        OnClientConnectedCallback += OnClientConnected;
        OnClientDisconnectCallback += OnClientDisconnect;
        
  
        bool result = StartClient();
        
        if (!result)
        {
            Debug.LogError("Failed to start client connection");
            isConnecting = false;
        }
        
        return result;
    }
    
    
    private void OnClientConnected(ulong clientId)
    {
        Debug.Log($"Successfully connected to server! Client ID: {clientId}");
        isConnecting = false;
        
        if (usingSteamNetworking)
        {
            Debug.Log("Connection established using Steam networking");
        }
    }
    
    private void OnClientDisconnect(ulong clientId)
    {
        Debug.Log($"Disconnected from server. Client ID: {clientId}");
        isConnecting = false;
        usingSteamNetworking = false;
    }
    
    private async Task ProcessSteamPlayerInfo()
    {
        try {
            
            CSteamID steamID = SteamUser.GetSteamID();
            string steamIdString = steamID.ToString();
            
            Debug.Log($"Steam ID retrieved: {steamIdString}");
            
      
            Player player = await PlayerService.GetPlayer(steamIdString);
            
     
            PlayerPrefs.SetString("Gamertag", player.Gamertag);
            PlayerPrefs.SetString("SteamID", steamIdString);
            PlayerPrefs.Save();
            
            Debug.Log($"Player retrieved/created: {player.Gamertag}");
        }
        catch (System.Exception e) {
            Debug.LogError($"Error retrieving Steam ID or player data: {e.Message}");
            ProcessPlayerPrefs();
        }
    }
    
    private void ProcessPlayerPrefs()
    {
        if (PlayerPrefs.HasKey("Gamertag")) {
            string gamertag = PlayerPrefs.GetString("Gamertag");
            Debug.Log($"Using cached player data: {gamertag}");
        }
    }
    
private void LoadMainMenu()
{
    Debug.Log($"Scene name to load: '{mainMenuSceneName}'");

    if (Application.CanStreamedLevelBeLoaded(mainMenuSceneName))
    {
    string sceneName = mainMenuSceneName;
    Debug.Log($"Loading main menu scene: {sceneName}");
    SceneManager.LoadScene(sceneName, LoadSceneMode.Single);
    }
    else
    {
        Debug.LogError($"Scene '{mainMenuSceneName}' is nOT in build settings or misspelled.");
    }
}


 
    public async void TestBasicConnection(string ip = null, int? port = null)
    {
        string targetIP = ip ?? defaultServerIP;
        int targetPort = port ?? defaultServerPort;
        
        try
        {
            Debug.Log($"Testing basic TCP connection to {targetIP}:{targetPort}...");
            
            using (var client = new System.Net.Sockets.TcpClient())
            {
                var connectTask = client.ConnectAsync(targetIP, targetPort);
                var timeoutTask = System.Threading.Tasks.Task.Delay(5000);
                
                if (await System.Threading.Tasks.Task.WhenAny(connectTask, timeoutTask) == timeoutTask)
                {
                    Debug.Log($"TCP connection to {targetIP}:{targetPort} timed out");
                    return;
                }
                
                if (client.Connected)
                {
                    Debug.Log($"TCP connection to {targetIP}:{targetPort} successful!");
                }
                else
                {
                    Debug.Log($"TCP connection to {targetIP}:{targetPort} failed (client reports not connected)");
                }
            }
        }
        catch (System.Exception ex)
        {
            Debug.LogError($"TCP connection test error: {ex.Message}");
        }
    }
}