using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using Crysome.Common.Model;
using Crysome.Common.Network.Packets;
using Crysome.Common.Network.Packets.Client;
using Crysome.Common.Network.Packets.Server;
using Crysome.Server.Model;
using Crysome.Server.Network;
using Microsoft.Win32;

namespace Crysome.Server.ViewModel;

public class FileExplorerViewModel : ViewModelBase, IDisposable
{
	private bool _downloadProgressVisible;

	private string _downloadStatusText;

	private double _downloadProgress;

	private string _pendingDownloadSavePath;

	private Stopwatch _downloadStopwatch;

	private readonly MainViewModel _mainVm;

	private bool _disposed;

	private string[] _drives;

	private FileSystemEntry _currentDirectory;

	private FileSystemEntry _selectedFile;

	private string _sortMode = "Name";

	public bool DownloadProgressVisible
	{
		get
		{
			return _downloadProgressVisible;
		}
		set
		{
			_downloadProgressVisible = value;
			OnPropertyChanged(() => DownloadProgressVisible);
		}
	}

	public string DownloadStatusText
	{
		get
		{
			return _downloadStatusText;
		}
		set
		{
			_downloadStatusText = value;
			OnPropertyChanged(() => DownloadStatusText);
		}
	}

	public double DownloadProgress
	{
		get
		{
			return _downloadProgress;
		}
		set
		{
			_downloadProgress = value;
			OnPropertyChanged(() => DownloadProgress);
		}
	}

	public ObservableCollection<FileSystemEntry> Files { get; set; }

	public ICollectionView FilesView { get; private set; }

	public Stack<FileSystemEntry> BackHistory { get; set; }

	public Stack<FileSystemEntry> ForwardHistory { get; set; }

	public bool CanGoBackward => BackHistory.Count > 0;

	public bool CanGoForward => ForwardHistory.Count > 0;

	public string[] Drives
	{
		get
		{
			return _drives;
		}
		set
		{
			_drives = value;
			OnPropertyChanged(() => Drives);
		}
	}

	public FileSystemEntry CurrentDirectory
	{
		get
		{
			return _currentDirectory;
		}
		set
		{
			_currentDirectory = value;
			OnPropertyChanged(() => CurrentDirectory);
		}
	}

	public FileSystemEntry SelectedFile
	{
		get
		{
			return _selectedFile;
		}
		set
		{
			_selectedFile = value;
			OnPropertyChanged(() => _selectedFile);
		}
	}

	public string SortMode
	{
		get
		{
			return _sortMode;
		}
		set
		{
			_sortMode = value ?? "Name";
			OnPropertyChanged(() => SortMode);
			ApplySort();
		}
	}

	public string[] SortOptions { get; } = new string[4] { "Name", "DateModified", "Size", "Type" };

	public ICommand NavigateCommand { get; set; }

	public ICommand NavigateSelectedCommand { get; set; }

	public ICommand OpenCommand { get; set; }

	public ICommand SaveAsCommand { get; set; }

	public ICommand UploadCommand { get; set; }

	public ICommand PropertiesCommand { get; set; }

	public ICommand NavigateUpCommand { get; set; }

	public ICommand NavigateForwardCommand { get; set; }

	public ICommand NavigateBackCommand { get; set; }

	public ICommand DeleteFileCommand { get; set; }

	public ClientInfo Client { get; set; }

	public ICommand GoBackToClientsCommand { get; set; }

	public FileExplorerViewModel(CrysomeServer server, ClientInfo client, MainViewModel mainVm)
	{
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Expected O, but got Unknown
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Expected O, but got Unknown
		FileExplorerViewModel fileExplorerViewModel = this;
		_mainVm = mainVm;
		Files = new ObservableCollection<FileSystemEntry>();
		FilesView = CollectionViewSource.GetDefaultView(Files);
		ApplySort();
		BackHistory = new Stack<FileSystemEntry>();
		ForwardHistory = new Stack<FileSystemEntry>();
		Client = client;
		_mainVm.ClientsVM.RegisterActiveFileExplorer(client.Owner, this);
		if (server.ClientCount > 0)
		{
			long num = _mainVm.ClientsVM.NextExplorerOpId();
			_mainVm.ClientsVM.RegisterGetDirectoryCallback(client.Owner, num, delegate(GetDirectoryResponsePacket p)
			{
				((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
				{
					fileExplorerViewModel.ApplyGetDirectoryResponse(p);
				});
			});
			client.Owner.SendPacket((IPacket)new GetDirectoryRequestPacket(string.Empty, num));
			long requestId = _mainVm.ClientsVM.NextExplorerOpId();
			_mainVm.ClientsVM.RegisterGetDrivesCallback(client.Owner, requestId, delegate(GetDrivesResponsePacket p)
			{
				((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
				{
					fileExplorerViewModel.ApplyGetDrivesResponse(p);
				});
			});
			client.Owner.SendPacket((IPacket)new GetDrivesRequestPacket
			{
				RequestId = requestId
			});
		}
		NavigateCommand = new RelayCommand<string>(NavigateWithHistory);
		NavigateSelectedCommand = new RelayCommand<string>(NavigateSelected);
		OpenCommand = new RelayCommand<string>(OpenSelected);
		SaveAsCommand = new RelayCommand<string>(SaveAsSelected);
		UploadCommand = new RelayCommand<string>(delegate
		{
			fileExplorerViewModel.UploadFile();
		});
		PropertiesCommand = new RelayCommand<string>(ShowProperties);
		NavigateUpCommand = new RelayCommand<string>(NavigateUp);
		NavigateForwardCommand = new RelayCommand<string>(NavigateForward);
		NavigateBackCommand = new RelayCommand<string>(NavigateBack);
		DeleteFileCommand = new RelayCommand<string>(DeleteFile);
		GoBackToClientsCommand = new RelayCommand<string>(delegate
		{
			mainVm.GoToClients();
		});
	}

	public void Dispose()
	{
		if (!_disposed)
		{
			_disposed = true;
			if (Client?.Owner != null)
			{
				_mainVm.ClientsVM.UnregisterActiveFileExplorer(Client.Owner, this);
			}
		}
	}

	private void ApplySort()
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		if (FilesView == null)
		{
			return;
		}
		using (FilesView.DeferRefresh())
		{
			((Collection<SortDescription>)(object)FilesView.SortDescriptions).Clear();
			switch (SortMode)
			{
			case "DateModified":
				((Collection<SortDescription>)(object)FilesView.SortDescriptions).Add(new SortDescription("LastWriteUtcTicks", ListSortDirection.Descending));
				break;
			case "Size":
				((Collection<SortDescription>)(object)FilesView.SortDescriptions).Add(new SortDescription("Size", ListSortDirection.Descending));
				break;
			case "Type":
				((Collection<SortDescription>)(object)FilesView.SortDescriptions).Add(new SortDescription("Type", ListSortDirection.Ascending));
				((Collection<SortDescription>)(object)FilesView.SortDescriptions).Add(new SortDescription("Name", ListSortDirection.Ascending));
				break;
			default:
				((Collection<SortDescription>)(object)FilesView.SortDescriptions).Add(new SortDescription("Name", ListSortDirection.Ascending));
				break;
			}
		}
	}

	public void ApplyGetDirectoryResponse(GetDirectoryResponsePacket directoryResponse)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Expected O, but got Unknown
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Expected O, but got Unknown
		Files.Clear();
		CurrentDirectory = new FileSystemEntry(directoryResponse.Name, directoryResponse.Path, 0L, (FileType)0, 0L, (byte[])null);
		OnPropertyChanged(() => CanGoBackward);
		OnPropertyChanged(() => CanGoForward);
		string[] folders = directoryResponse.Folders;
		int num = ((folders != null) ? folders.Length : 0);
		long[] folderLastWriteUtcTicks = directoryResponse.FolderLastWriteUtcTicks;
		byte[][] folderIconPng = directoryResponse.FolderIconPng;
		for (int num2 = 0; num2 < num; num2++)
		{
			long num3 = ((folderLastWriteUtcTicks != null && num2 < folderLastWriteUtcTicks.Length) ? folderLastWriteUtcTicks[num2] : 0);
			byte[] array = ((folderIconPng != null && num2 < folderIconPng.Length) ? folderIconPng[num2] : null);
			Files.Add(new FileSystemEntry(directoryResponse.Folders[num2], Path.Combine(CurrentDirectory.Path, directoryResponse.Folders[num2]), 0L, (FileType)0, num3, array));
		}
		string[] files = directoryResponse.Files;
		int num4 = ((files != null) ? files.Length : 0);
		long[] fileLastWriteUtcTicks = directoryResponse.FileLastWriteUtcTicks;
		byte[][] fileIconPng = directoryResponse.FileIconPng;
		for (int num5 = 0; num5 < num4; num5++)
		{
			long num6 = ((fileLastWriteUtcTicks != null && num5 < fileLastWriteUtcTicks.Length) ? fileLastWriteUtcTicks[num5] : 0);
			byte[] array2 = ((fileIconPng != null && num5 < fileIconPng.Length) ? fileIconPng[num5] : null);
			Files.Add(new FileSystemEntry(directoryResponse.Files[num5], Path.Combine(CurrentDirectory.Path, directoryResponse.Files[num5]), directoryResponse.FileSizes[num5], (FileType)1, num6, array2));
		}
		ApplySort();
	}

	public void ApplyGetDrivesResponse(GetDrivesResponsePacket getDrivesPacket)
	{
		Drives = getDrivesPacket.Drives;
	}

	public void ApplyNotifyStatus(NotifyStatusResponsePacket statusPacket)
	{
		_mainVm.ClientsVM?.EnqueueStatus(statusPacket.StatusMessage);
	}

	private void Navigate(string path)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		long num = _mainVm.ClientsVM.NextExplorerOpId();
		_mainVm.ClientsVM.RegisterGetDirectoryCallback(Client.Owner, num, delegate(GetDirectoryResponsePacket p)
		{
			((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
			{
				ApplyGetDirectoryResponse(p);
			});
		});
		Client.Owner.SendPacket((IPacket)new GetDirectoryRequestPacket(path, num));
	}

	private void NavigateWithHistory(string path)
	{
		if (CurrentDirectory != null && path != CurrentDirectory.Path)
		{
			BackHistory.Push(CurrentDirectory);
		}
		Navigate(path);
	}

	private void NavigateSelected(string s)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		if (SelectedFile != null && (int)SelectedFile.Type == 0)
		{
			NavigateWithHistory(SelectedFile.Path);
		}
	}

	private void NavigateUp(string s)
	{
		NavigateWithHistory(Path.Combine(CurrentDirectory.Path, ".."));
	}

	private void NavigateForward(string s)
	{
		BackHistory.Push(CurrentDirectory);
		FileSystemEntry val = ForwardHistory.Pop();
		Navigate(val.Path);
	}

	private void NavigateBack(string s)
	{
		ForwardHistory.Push(CurrentDirectory);
		FileSystemEntry val = BackHistory.Pop();
		Navigate(val.Path);
	}

	private void DeleteFile(string s)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		if (SelectedFile != null)
		{
			FileSystemEntry selectedFile = SelectedFile;
			if (MessageBox.Show("Delete " + selectedFile.Name + "?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
			{
				Client.Owner.SendPacket((IPacket)new DeleteFileRequestPacket(selectedFile.Path));
				_mainVm.ClientsVM?.EnqueueStatus("Delete sent for " + selectedFile.Name);
			}
		}
	}

	private void OpenSelected(string s)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		if (SelectedFile != null && (int)SelectedFile.Type == 0)
		{
			NavigateWithHistory(SelectedFile.Path);
		}
	}

	private void SaveAsSelected(string s)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Expected O, but got Unknown
		if (SelectedFile == null)
		{
			return;
		}
		if ((int)SelectedFile.Type == 0)
		{
			_mainVm.ClientsVM?.EnqueueStatus("Select a file to download.");
			return;
		}
		SaveFileDialog saveFileDialog = new SaveFileDialog
		{
			FileName = SelectedFile.Name,
			Filter = "All files|*.*",
			DefaultExt = Path.GetExtension(SelectedFile.Name)
		};
		if (saveFileDialog.ShowDialog() != true)
		{
			return;
		}
		string fileName = saveFileDialog.FileName;
		_pendingDownloadSavePath = fileName;
		DownloadProgressVisible = true;
		DownloadProgress = 0.0;
		DownloadStatusText = "Downloading...";
		_downloadStopwatch = Stopwatch.StartNew();
		long num = _mainVm.ClientsVM.NextExplorerOpId();
		_mainVm.ClientsVM.RegisterReadFileCallback(Client.Owner, num, delegate(ReadFileResponsePacket resp)
		{
			((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
			{
				CompleteDownloadSave(resp);
			});
		});
		Client.Owner.SendPacket((IPacket)new ReadFileRequestPacket(SelectedFile.Path, num));
	}

	private void CompleteDownloadSave(ReadFileResponsePacket resp)
	{
		string pendingDownloadSavePath = _pendingDownloadSavePath;
		_pendingDownloadSavePath = null;
		try
		{
			if (resp.Success && resp.Data != null)
			{
				File.WriteAllBytes(pendingDownloadSavePath, resp.Data);
				TimeSpan timeSpan = _downloadStopwatch?.Elapsed ?? TimeSpan.Zero;
				_mainVm.ClientsVM?.EnqueueStatus($"Saved to {pendingDownloadSavePath} ({resp.Data.Length / 1024} KB in {timeSpan.TotalSeconds:F1}s)");
			}
			else
			{
				_mainVm.ClientsVM?.EnqueueStatus("Download failed: " + (((resp != null) ? resp.ErrorMessage : null) ?? "Unknown error"));
			}
		}
		catch (Exception ex)
		{
			_mainVm.ClientsVM?.EnqueueStatus("Save failed: " + ex.Message);
		}
		DownloadProgressVisible = false;
		DownloadStatusText = "";
	}

	private void UploadFile()
	{
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Expected O, but got Unknown
		if (CurrentDirectory == null)
		{
			return;
		}
		OpenFileDialog openFileDialog = new OpenFileDialog
		{
			Filter = "All files|*.*"
		};
		if (openFileDialog.ShowDialog() != true)
		{
			return;
		}
		byte[] array;
		try
		{
			array = File.ReadAllBytes(openFileDialog.FileName);
		}
		catch (Exception ex)
		{
			_mainVm.ClientsVM?.EnqueueStatus("Upload read error: " + ex.Message);
			return;
		}
		long num = (long)_mainVm.ClientsVM.Store.Settings.MaxSendFileSizeMB * 1024L * 1024;
		if (num > 0 && array.Length > num)
		{
			_mainVm.ClientsVM?.EnqueueStatus("File too large (limit " + _mainVm.ClientsVM.Store.Settings.MaxSendFileSizeMB + " MB)");
			return;
		}
		string name = Path.GetFileName(openFileDialog.FileName);
		string destPath = Path.Combine(CurrentDirectory.Path, name);
		long transferId = _mainVm.ClientsVM.NextExplorerOpId();
		DownloadProgressVisible = true;
		DownloadStatusText = "Uploading...";
		_mainVm.ClientsVM.RegisterWriteFileCallback(Client.Owner, transferId, delegate(WriteFileResponsePacket resp)
		{
			((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
			{
				DownloadProgressVisible = false;
				DownloadStatusText = "";
				if (resp.Success)
				{
					_mainVm.ClientsVM?.EnqueueStatus("Uploaded " + name);
					Navigate(CurrentDirectory.Path);
				}
				else
				{
					_mainVm.ClientsVM?.EnqueueStatus("Upload failed: " + (resp.ErrorMessage ?? "?"));
				}
			});
		});
		Client.Owner.SendPacket((IPacket)new WriteFileRequestPacket
		{
			DestPath = destPath,
			TransferId = transferId,
			Data = array
		});
	}

	private void ShowProperties(string s)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		if (SelectedFile != null)
		{
			FileSystemEntry selectedFile = SelectedFile;
			string value = (((int)selectedFile.Type == 0) ? "—" : FormatFileSize(selectedFile.Size));
			string value2 = ((selectedFile.LastWriteUtcTicks > 0) ? new DateTime(selectedFile.LastWriteUtcTicks, DateTimeKind.Utc).ToLocalTime().ToString("yyyy-MM-dd HH:mm") : "—");
			MessageBox.Show($"Name: {selectedFile.Name}\nPath: {selectedFile.Path}\nType: {selectedFile.Type}\nSize: {value}\nModified: {value2}", "Properties", MessageBoxButton.OK, MessageBoxImage.Asterisk);
		}
	}

	private static string FormatFileSize(long bytes)
	{
		if (bytes < 1024)
		{
			return bytes + " B";
		}
		if (bytes < 1048576)
		{
			return ((double)bytes / 1024.0).ToString("F1") + " KB";
		}
		if (bytes < 1073741824)
		{
			return ((double)bytes / 1048576.0).ToString("F1") + " MB";
		}
		return ((double)bytes / 1073741824.0).ToString("F1") + " GB";
	}
}
