Editor/AssetFileNode.cs
using Editor;
using Sandbox;
using Sandbox.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Numerics;
using System.Runtime.Intrinsics.X86;
using static Sandbox.Connection;
using static Sandbox.Internal.IControlSheet;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace GeneralGame.Editor;

/// <summary>
/// Tree node representing a file/asset in the asset browser
/// </summary>
public class AssetFileNode : TreeNode
{
    public string FullPath { get; }
    public string FileName { get; }
    public string Extension { get; }
    public Asset Asset { get; private set; }

    public override bool HasChildren => false;
    public override string Name => Path.GetFileNameWithoutExtension(FileName);
    public override bool CanEdit => true;




    private static readonly Dictionary<string, string> ExtensionIcons = new()
    {
        // Models
        { ".vmdl", "view_in_ar" },
        { ".fbx", "view_in_ar" },
        { ".obj", "view_in_ar" },
        { ".gltf", "view_in_ar" },
        { ".glb", "view_in_ar" },
        
        // Textures
        { ".png", "image" },
        { ".jpg", "image" },
        { ".jpeg", "image" },
        { ".tga", "image" },
        { ".vtex", "image" },
        { ".psd", "image" },

        // Materials
        { ".vmat", "texture" },

        // Sounds
        { ".wav", "audiotrack" },
        { ".mp3", "audiotrack" },
        { ".ogg", "audiotrack" },
        { ".vsnd", "audiotrack" },

        // Code
        { ".cs", "code" },
        { ".razor", "code" },
        { ".scss", "style" },
        { ".css", "style" },
        { ".shader", "gradient" },
        { ".shdrgrph", "gradient" },

        // Prefabs & Scenes
        { ".prefab", "inventory_2" },
        { ".scene", "landscape" },

        // Data
        { ".json", "data_object" },
        { ".xml", "data_object" },
        { ".txt", "description" },
        { ".md", "description" },

        // Resources
        { ".item", "category" },
        { ".clothing", "checkroom" },
        { ".weapon", "sports_martial_arts" },

        // Other
        { ".particle", "blur_on" },
        { ".vanmgrph", "animation" },
        { ".vpost", "auto_fix_high" }
    };

    private static readonly Dictionary<string, Color> ExtensionColors = new()
    {
        { ".cs", new Color(0.4f, 0.7f, 1.0f) },      // Blue for C#
        { ".razor", new Color(0.6f, 0.4f, 0.9f) },  // Purple for Razor
        { ".shader", new Color(0.3f, 0.9f, 0.5f) }, // Green for shaders
        { ".vmdl", new Color(0.9f, 0.6f, 0.3f) },   // Orange for models
        { ".vmat", new Color(0.9f, 0.4f, 0.6f) },   // Pink for materials
        { ".prefab", new Color(0.3f, 0.8f, 0.9f) }, // Cyan for prefabs
        { ".scene", new Color(0.9f, 0.9f, 0.3f) },  // Yellow for scenes
    };

    public AssetFileNode(string path) : base()
    {
        FullPath = Path.GetFullPath(path);
        FileName = Path.GetFileName(path);
        Extension = Path.GetExtension(path).ToLowerInvariant();
        Value = this;

        // Try to find associated asset
        Asset = AssetSystem.FindByPath(path);
    }

    public override void OnPaint(VirtualWidget item)
    {
        PaintSelection(item);

        var rect = item.Rect;

        // Get icon
        var icon = GetIcon();
        var iconColor = GetIconColor();

        // Draw icon
        Paint.SetPen(iconColor);
        Paint.DrawIcon(rect, icon, 14, TextFlag.LeftCenter);

        rect.Left += 20;

        // Draw filename
        Paint.SetPen(Theme.Text);
        Paint.SetDefaultFont(8, 400);

        var nameWithoutExt = Path.GetFileNameWithoutExtension(FileName);
        var nameRect = Paint.MeasureText(rect, nameWithoutExt, TextFlag.LeftCenter);
        Paint.DrawText(rect, nameWithoutExt, TextFlag.LeftCenter);

        // Draw extension in dimmer color
        rect.Left += nameRect.Width + 1;
        Paint.SetPen(Theme.Text.WithAlpha(0.4f));
        Paint.SetDefaultFont(7, 400);
        Paint.DrawText(rect, Extension, TextFlag.LeftCenter);
    }

    private string GetIcon()
    {
        // Use extension-based icon
        if (ExtensionIcons.TryGetValue(Extension, out var icon))
        {
            return icon;
        }

        return "description"; // Default file icon
    }

    private Color GetIconColor()
    {
        // Use asset type color if available
        if (Asset?.AssetType?.Color != null && Asset.AssetType.Color != default)
        {
            return Asset.AssetType.Color;
        }

        // Use extension-based color
        if (ExtensionColors.TryGetValue(Extension, out var color))
        {
            return color;
        }

        return Theme.Text.WithAlpha(0.7f);
    }

    public override bool OnContextMenu()
    {
        var menu = new ContextMenu(null);

        // Open options
        if (Asset != null)
        {
            menu.AddOption("Open in Editor", "edit", () => Asset.OpenInEditor());
        }
        else
        {
            menu.AddOption("Open", "open_in_new", () => EditorUtility.OpenFolder(FullPath));
        }
        menu.AddOption("Show in Explorer", "folder_open", () => EditorUtility.OpenFileFolder(FullPath));

        menu.AddSeparator();

        // Copy options
        if (Asset != null)
        {
            menu.AddOption("Copy Relative Path", "content_paste_go", () => EditorUtility.Clipboard.Copy(Asset.RelativePath));
        }
        menu.AddOption("Copy Absolute Path", "content_paste", () => EditorUtility.Clipboard.Copy(FullPath));

        // Asset-type specific options (Create Material, Create Texture, etc.)
        AssetContextMenuHelper.AddAssetTypeOptions(menu, Asset);

        menu.AddSeparator();

        // Edit options
        menu.AddOption("Rename", "edit", () => ShowRenameDialog());
        menu.AddOption("Duplicate", "file_copy", () => DuplicateFile());

        menu.AddSeparator();

        // Create submenu for quick asset creation in same folder
        var parentFolder = Path.GetDirectoryName(FullPath);
        if (!string.IsNullOrEmpty(parentFolder))
        {
            var createMenu = menu.AddMenu("Create", "add");
            AssetCreator.AddOptions(createMenu, parentFolder);
            menu.AddSeparator();
        }

        menu.AddOption("Delete", "delete", () =>
        {
            var confirm = new PopupWindow(
                "Delete File",
                $"Are you sure you want to delete '{FileName}'?",
                "Cancel",
                new Dictionary<string, Action>()
                {
                    { "Delete", () =>
                        {
                            try
                            {
                                DeleteFileWithCompiled();
                                Parent?.Dirty();
                            }
                            catch (Exception ex)
                            {
                                Log.Error($"Failed to delete file: {ex.Message}");
                            }
                        }
                    }
                }
            );
            confirm.Show();
        });

        menu.OpenAtCursor();
        return true;
    }

    private void ShowRenameDialog()
    {
        var dialog = new RenameDialog("Rename File", Path.GetFileNameWithoutExtension(FileName));
        dialog.OnConfirm = (newName) =>
        {
            if (string.IsNullOrWhiteSpace(newName))
                return;

            // Preserve extension if not provided
            if (!Path.HasExtension(newName))
            {
                newName += Extension;
            }

            if (newName == FileName)
                return;

            var newPath = Path.Combine(Path.GetDirectoryName(FullPath), newName);
            try
            {
                File.Move(FullPath, newPath);
                Parent?.Dirty();
            }
            catch (Exception ex)
            {
                Log.Error($"Failed to rename file: {ex.Message}");
            }
        };
        dialog.Show();
    }

    private void DuplicateFile()
    {
        try
        {
            var directory = Path.GetDirectoryName(FullPath);
            var nameWithoutExt = Path.GetFileNameWithoutExtension(FileName);
            var extension = Path.GetExtension(FileName);

            var newName = $"{nameWithoutExt}_copy{extension}";
            var newPath = Path.Combine(directory, newName);

            var counter = 1;
            while (File.Exists(newPath))
            {
                newName = $"{nameWithoutExt}_copy{counter++}{extension}";
                newPath = Path.Combine(directory, newName);
            }

            File.Copy(FullPath, newPath);
            Parent?.Dirty();
        }
        catch (Exception ex)
        {
            Log.Error($"Failed to duplicate file: {ex.Message}");
        }
    }

    /// <summary>
    /// Delete the file and its compiled _c version if it exists
    /// </summary>
    private void DeleteFileWithCompiled()
    {
        // If we have an Asset, use its Delete method which handles compiled files
        if (Asset != null)
        {
            Asset.Delete();
            return;
        }

        // Otherwise manually delete the file and any compiled version
        File.Delete(FullPath);

        // Check for compiled _c version and delete it too
        var compiledPath = FullPath + "_c";
        if (File.Exists(compiledPath))
        {
            File.Delete(compiledPath);
        }
    }

    public override void OnRename(VirtualWidget item, string text, List<TreeNode> selection = null)
    {
        if (string.IsNullOrWhiteSpace(text))
            return;

        // Preserve extension if not provided
        var newName = text;
        if (!Path.HasExtension(newName))
        {
            newName += Extension;
        }

        if (newName == FileName)
            return;

        var newPath = Path.Combine(Path.GetDirectoryName(FullPath), newName);

        try
        {
            if (Asset != null)
            {
                EditorUtility.MoveAssetToDirectory(Asset, Path.GetDirectoryName(newPath));
            }
            else
            {
                File.Move(FullPath, newPath);
            }
            Parent?.Dirty();
        }
        catch (Exception ex)
        {
            Log.Error($"Failed to rename file: {ex.Message}");
        }
    }

    public override bool OnDragStart()
    {
        var drag = new Drag(TreeView);

        if (Asset != null)
        {
            drag.Data.Object = Asset;
        }

        drag.Data.Text = FullPath;
        drag.Data.Url = new Uri("file:///" + FullPath);
        drag.Execute();
        return true;
    }

    public override void OnActivated()
    {
        if (Asset != null)
        {
            Asset.OpenInEditor();
        }
        else
        {
            EditorUtility.OpenFolder(FullPath);
        }
    }

    /// <summary>
    /// Check if this file matches the search filter
    /// </summary>
    public bool MatchesFilter(string filter)
    {
        if (string.IsNullOrEmpty(filter))
            return true;

        // Check filename
        if (FileName.ToLowerInvariant().Contains(filter))
            return true;

        // Check asset type
        if (Asset?.AssetType?.FriendlyName?.ToLowerInvariant().Contains(filter) == true)
            return true;

        return false;
    }

    public override string GetTooltip()
    {
        var tip = FullPath;

        if (Asset != null)
        {
            tip += $"\nType: {Asset.AssetType?.FriendlyName ?? "Unknown"}";
        }

        var fileInfo = new FileInfo(FullPath);
        if (fileInfo.Exists)
        {
            tip += $"\nSize: {FormatFileSize(fileInfo.Length)}";
            tip += $"\nModified: {fileInfo.LastWriteTime:g}";
        }

        return tip;
    }

    private static string FormatFileSize(long bytes)
    {
        string[] sizes = { "B", "KB", "MB", "GB" };
        int order = 0;
        double size = bytes;
        while (size >= 1024 && order < sizes.Length - 1)
        {
            order++;
            size /= 1024;
        }
        return $"{size:0.##} {sizes[order]}";
    }
}