Code/XGUI/Elements/ExtraElements/FileBrowserView.cs
using Sandbox;
using Sandbox.UI;
using System;
using System.Collections.Generic;
using System.Linq;

namespace XGUI;

/// <summary>
/// View modes available for FileBrowserView
/// </summary>
public enum FileBrowserViewMode
{
	Icons,
	List,
	Details
}

/// <summary>
/// A panel that displays files in a folder with different view modes (Icons, List, Details).
/// </summary>
public class FileBrowserView : Panel
{
	public BaseFileSystem CurrentFileSystem;
	public string CurrentPath;
	public List<FileItem> FileItems = new();
	public ListView ListView;

	// View mode properties
	private FileBrowserViewMode _viewMode = FileBrowserViewMode.Icons;
	public FileBrowserViewMode ViewMode
	{
		get => _viewMode;
		set
		{
			if ( _viewMode == value )
				return;

			_viewMode = value;
			UpdateViewMode();
			if ( CurrentFileSystem != null && !string.IsNullOrEmpty( CurrentPath ) )
				Refresh();
		}
	}

	// Events
	public event Action<string> OnFileSelected;
	public event Action<string> OnDirectorySelected;
	public event Action<string> OnFileOpened;
	public event Action<string> OnDirectoryOpened;
	public event Action<string> OnNavigateTo;
	public event Action OnPreAddFiles;
	public event Action OnPostAddFiles;
	public event Action<FileBrowserViewMode> OnViewModeChanged;

	public FileBrowserView()
	{
		AddClass( "file-browser-view" );

		// Create the ListView component
		ListView = AddChild<ListView>();
		ListView.AddClass( "file-browser-listview" );

		// Add standard columns for details view
		ListView.AddColumn( "Name", "name", 300 );
		ListView.AddColumn( "Type", "type", 150 );
		ListView.AddColumn( "Size", "size", 100 );

		// Connect ListView events to FileBrowserView events
		ListView.OnItemSelected += OnListViewItemSelected;
		ListView.OnItemActivated += OnListViewItemActivated;

		// Initialize with Icons view
		UpdateViewMode();
	}

	protected void OnListViewItemSelected( ListView.ListViewItem item )
	{
		var fileItem = item.Data as FileItem;
		if ( fileItem != null )
		{
			if ( fileItem.IsDirectory )
			{
				OnDirectorySelected?.Invoke( fileItem.FullPath );
			}
			else
			{
				OnFileSelected?.Invoke( fileItem.FullPath );
			}
		}
	}

	protected void OnListViewItemActivated( ListView.ListViewItem item )
	{
		var fileItem = item.Data as FileItem;
		if ( fileItem != null )
		{
			if ( fileItem.IsDirectory )
			{
				OnDirectoryOpened?.Invoke( fileItem.FullPath );
			}
			else
			{
				OnFileOpened?.Invoke( fileItem.FullPath );
			}
		}
	}

	public void UpdateViewMode()
	{
		// Map FileBrowserViewMode to ListView.ListViewMode
		ListView.ViewMode = ViewMode switch
		{
			FileBrowserViewMode.Icons => ListView.ListViewMode.Icons,
			FileBrowserViewMode.List => ListView.ListViewMode.List,
			FileBrowserViewMode.Details => ListView.ListViewMode.Details,
			_ => ListView.ListViewMode.Icons
		};

		// Notify about view mode change
		OnViewModeChanged?.Invoke( ViewMode );
	}

	/// <summary>
	/// Switches between view modes (Icons, List, Details)
	/// </summary>
	public void CycleViewMode()
	{
		ViewMode = ViewMode switch
		{
			FileBrowserViewMode.Icons => FileBrowserViewMode.List,
			FileBrowserViewMode.List => FileBrowserViewMode.Details,
			FileBrowserViewMode.Details => FileBrowserViewMode.Icons,
			_ => FileBrowserViewMode.Icons
		};
	}

	/// <summary>
	/// Properly raises the NavigateTo event
	/// </summary>
	public void RaiseNavigateToEvent( string path )
	{
		OnNavigateTo?.Invoke( path );
	}

	public void NavigateTo( string path )
	{
		CurrentPath = path;
		RaiseNavigateToEvent( path );
		Refresh();
	}

	public virtual void SetupHeader()
	{
		// Not needed anymore as ListView handles its own header
	}

	public virtual void Refresh()
	{
		FileItems.Clear();
		ListView.Items.Clear();

		// Important: Update the ListView UI
		ListView.DeleteChildren();
		ListView.InitializeHeader();

		if ( string.IsNullOrEmpty( CurrentPath ) || CurrentFileSystem == null )
			return;

		if ( !CurrentFileSystem.DirectoryExists( CurrentPath ) )
			return;

		try
		{
			// Get directories first
			List<string> directories = CurrentFileSystem.FindDirectory( CurrentPath ).ToList();

			// Get files
			List<string> files = CurrentFileSystem.FindFile( CurrentPath ).ToList();

			// Sort directories and files (default sort is by name)
			directories.Sort( ( a, b ) => string.Compare( System.IO.Path.GetFileName( a ), System.IO.Path.GetFileName( b ) ) );
			files.Sort( ( a, b ) => string.Compare( System.IO.Path.GetFileName( a ), System.IO.Path.GetFileName( b ) ) );

			OnPreAddFiles?.Invoke();

			// Display directories first
			foreach ( var dir in directories )
			{
				AddDirectoryToView( dir );
			}

			// Then display files
			foreach ( var file in files )
			{
				AddFileToView( file );
			}

			OnPostAddFiles?.Invoke();
		}
		catch ( Exception ex )
		{
			Log.Error( $"Error accessing directory: {ex.Message}" );
		}
	}

	public virtual void AddFileToView( string file, bool isFullPath = false, string nameOverride = "" )
	{
		var fullPath = CurrentPath + "/" + file;
		if ( isFullPath )
		{
			fullPath = file;
		}
		var fileName = System.IO.Path.GetFileName( file );
		if ( !string.IsNullOrEmpty( nameOverride ) )
		{
			fileName = nameOverride;
		}

		// Create the file item data object
		var fileItem = new FileItem
		{
			Name = fileName,
			FullPath = fullPath,
			IsDirectory = false
		};
		FileItems.Add( fileItem );

		// Create subItems for ListView
		var subItems = new List<string>
		{
			fileName,
			GetFileType( fileName, false ),
			GetFileSize( false )
		};

		// Add to ListView
		ListView.AddItem( fileItem, subItems );

		// Configure icon for the newly added item
		var listViewItem = ListView.Items.LastOrDefault();
		if ( listViewItem?.IconPanel != null )
		{
			string extension = System.IO.Path.GetExtension( fileName );
			int iconSize = ViewMode == FileBrowserViewMode.Icons ? 32 : 16;
			listViewItem.IconPanel.SetFileIcon( extension, iconSize );
		}
	}

	public virtual void AddDirectoryToView( string dir, bool isFullPath = false, string nameOverride = "" )
	{
		var fullPath = CurrentPath + "/" + dir;
		if ( isFullPath )
		{
			fullPath = dir;
		}
		var dirName = System.IO.Path.GetFileName( dir );
		if ( !string.IsNullOrEmpty( nameOverride ) )
		{
			dirName = nameOverride;
		}

		// Create the directory item data object
		var dirItem = new FileItem
		{
			Name = dirName,
			FullPath = fullPath,
			IsDirectory = true
		};
		FileItems.Add( dirItem );

		// Create subItems for ListView
		var subItems = new List<string>
		{
			dirName,
			GetFileType( dirName, true ),
			GetFileSize( true )
		};

		// Add to ListView
		ListView.AddItem( dirItem, subItems );

		// Configure icon for the newly added item
		var listViewItem = ListView.Items.LastOrDefault();
		if ( listViewItem?.IconPanel != null )
		{
			int iconSize = ViewMode == FileBrowserViewMode.Icons ? 32 : 16;
			listViewItem.IconPanel.SetFolderIcon( "folder", iconSize );
		}
	}

	private string GetFileType( string name, bool isDirectory )
	{
		if ( isDirectory )
			return "File Folder";

		string extension = System.IO.Path.GetExtension( name ).ToLower();
		return !string.IsNullOrEmpty( extension ) ? extension.Substring( 1 ).ToUpper() + " File" : "File";
	}

	private string GetFileSize( bool isDirectory )
	{
		return isDirectory ? "" : "";  // Could implement file size calculation if needed
	}

	public void SelectItem( FileItem item )
	{
		// Find the ListView item that corresponds to this FileItem
		foreach ( var listViewItem in ListView.Items )
		{
			if ( listViewItem.Data == item )
			{
				ListView.SelectItem( listViewItem );
				break;
			}
		}
	}

	public void UnselectAll()
	{
		// ListView doesn't have explicit UnselectAll, so we'll just clear our tracking
		foreach ( var item in ListView.Items )
		{
			item.SetSelected( false );
		}
	}

	protected override void OnRightClick( MousePanelEvent e )
	{
		base.OnRightClick( e );
		// Right-click handling is implemented in derived classes
	}

	/// <summary>
	/// Data class representing a file or directory item
	/// </summary>
	public class FileItem
	{
		public string Name { get; set; }
		public string FullPath { get; set; }
		public bool IsDirectory { get; set; }
	}
}