using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using NexusShell.Models;
using NexusShell.Services;

namespace NexusShell.ViewModels;

public sealed class NexusFilesViewModel : INotifyPropertyChanged
{
    private readonly NexusFileSystemService _fileSystem;
    private readonly NexusNavigationService _navigation;
    private readonly NexusSearchService _search;
    private readonly NexusFavoritesService _favorites;
    private readonly NexusPreviewService _preview;
    private readonly NexusFileOpenService _fileOpen;
    private string _searchQuery = string.Empty;
    private string _statusMessage = string.Empty;
    private FileSystemItem? _selectedItem;
    private NexusPreviewState _previewState;
    private IReadOnlyList<FileSystemItem> _allItems = [];

    public NexusFilesViewModel(
        NexusFileSystemService fileSystem,
        NexusNavigationService navigation,
        NexusSearchService search,
        NexusFavoritesService favorites,
        NexusPreviewService preview,
        NexusFileOpenService fileOpen)
    {
        _fileSystem = fileSystem;
        _navigation = navigation;
        _search = search;
        _favorites = favorites;
        _preview = preview;
        _fileOpen = fileOpen;
        _previewState = preview.BuildPreview(null);

        Items = [];
        Breadcrumbs = [];
        FavoriteItems = [];
        ThisPcItems = [];
        NexusItems = [];

        CloseCommand = new RelayCommand(_ => CloseRequested?.Invoke(this, EventArgs.Empty));
        RefreshCommand = new RelayCommand(_ => Reload());
        GoBackCommand = new RelayCommand(_ => GoBack(), _ => CanGoBack);
        GoForwardCommand = new RelayCommand(_ => GoForward(), _ => CanGoForward);
        GoUpCommand = new RelayCommand(_ => GoUp(), _ => CanGoUp);
        OpenSelectedCommand = new RelayCommand(_ => OpenSelected(), _ => SelectedItem is not null);
        NavigateCommand = new RelayCommand(p => NavigateTo(p as string));
        NavigateSegmentCommand = new RelayCommand(p => NavigateTo(p as string));
        OpenItemCommand = new RelayCommand(p => OpenItem(p as FileSystemItem));
        TogglePinCommand = new RelayCommand(p => TogglePin(p as string));
        ClearSearchCommand = new RelayCommand(_ => SearchQuery = string.Empty, _ => !string.IsNullOrWhiteSpace(SearchQuery));

        _favorites.FavoritesChanged += (_, _) => RebuildNav();

        RebuildNav();
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    public event EventHandler? CloseRequested;

    public ObservableCollection<FileSystemItem> Items { get; }
    public ObservableCollection<NexusPathSegment> Breadcrumbs { get; }
    public ObservableCollection<NexusNavItem> FavoriteItems { get; }
    public ObservableCollection<NexusNavItem> ThisPcItems { get; }
    public ObservableCollection<NexusNavItem> NexusItems { get; }

    public string CurrentPath => _navigation.CurrentPath;

    public bool CanGoBack => _navigation.CanGoBack;

    public bool CanGoForward => _navigation.CanGoForward;

    public bool CanGoUp => _fileSystem.GetParentPath(CurrentPath) is not null ||
                           (!string.Equals(CurrentPath, NexusPaths.ThisPc, StringComparison.OrdinalIgnoreCase) &&
                            !string.Equals(CurrentPath, _fileSystem.GetDocumentsPath(), StringComparison.OrdinalIgnoreCase));

    public string SearchQuery
    {
        get => _searchQuery;
        set
        {
            if (_searchQuery == value)
            {
                return;
            }

            _searchQuery = value;
            OnPropertyChanged();
            ApplySearchFilter();
        }
    }

    public string StatusMessage
    {
        get => _statusMessage;
        private set { _statusMessage = value; OnPropertyChanged(); }
    }

    public FileSystemItem? SelectedItem
    {
        get => _selectedItem;
        set
        {
            _selectedItem = value;
            PreviewState = _preview.BuildPreview(value);
            OnPropertyChanged();
        }
    }

    public NexusPreviewState PreviewState
    {
        get => _previewState;
        private set { _previewState = value; OnPropertyChanged(); }
    }

    public ICommand CloseCommand { get; }
    public ICommand RefreshCommand { get; }
    public ICommand GoBackCommand { get; }
    public ICommand GoForwardCommand { get; }
    public ICommand GoUpCommand { get; }
    public ICommand OpenSelectedCommand { get; }
    public ICommand NavigateCommand { get; }
    public ICommand NavigateSegmentCommand { get; }
    public ICommand OpenItemCommand { get; }
    public ICommand TogglePinCommand { get; }
    public ICommand ClearSearchCommand { get; }

    public void OpenLocation(string? hint)
    {
        var path = _navigation.ResolveInitialPath(hint);
        _navigation.ResetHistory(path);
        NavigateTo(path, recordHistory: false);
    }

    public void NavigateTo(string? path, bool recordHistory = true)
    {
        if (string.IsNullOrWhiteSpace(path))
        {
            return;
        }

        var resolved = ResolveForNavigation(path);
        _navigation.NavigateTo(resolved, recordHistory);
        SearchQuery = string.Empty;
        Reload();
        NotifyNavigationState();
    }

    private string ResolveForNavigation(string path)
    {
        if (string.Equals(path, NexusPaths.ThisPc, StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, NexusPaths.Recent, StringComparison.OrdinalIgnoreCase))
        {
            return path;
        }

        if (path.StartsWith("nexus:", StringComparison.OrdinalIgnoreCase))
        {
            return _fileSystem.ResolveLocationId(path);
        }

        return path;
    }

    private void GoBack()
    {
        if (_navigation.TryGoBack(out var path))
        {
            SearchQuery = string.Empty;
            Reload();
            NotifyNavigationState();
        }
    }

    private void GoForward()
    {
        if (_navigation.TryGoForward(out _))
        {
            SearchQuery = string.Empty;
            Reload();
            NotifyNavigationState();
        }
    }

    private void GoUp()
    {
        var parent = _fileSystem.GetParentPath(CurrentPath);
        if (parent is null)
        {
            if (!string.Equals(CurrentPath, NexusPaths.ThisPc, StringComparison.OrdinalIgnoreCase))
            {
                NavigateTo(NexusPaths.ThisPc);
            }

            return;
        }

        NavigateTo(parent);
    }

    private void Reload()
    {
        _allItems = _fileSystem.ListLocation(CurrentPath, _navigation.RecentPaths);
        ApplySearchFilter();
        UpdateBreadcrumbs();
    }

    private void ApplySearchFilter()
    {
        Items.Clear();
        var filtered = _search.SearchLocal(SearchQuery, _allItems);
        foreach (var item in filtered)
        {
            Items.Add(item);
        }

        StatusMessage = string.IsNullOrWhiteSpace(SearchQuery)
            ? Items.Count switch
            {
                0 => "Mappen er tom.",
                1 => "1 element",
                _ => $"{Items.Count} elementer",
            }
            : Items.Count switch
            {
                0 => $"Ingen resultater for \"{SearchQuery.Trim()}\"",
                1 => "1 resultat",
                _ => $"{Items.Count} resultater",
            };
    }

    private void UpdateBreadcrumbs()
    {
        Breadcrumbs.Clear();
        foreach (var segment in _navigation.GetBreadcrumbs(CurrentPath))
        {
            Breadcrumbs.Add(segment);
        }
    }

    private void RebuildNav()
    {
        FavoriteItems.Clear();
        foreach (var item in _favorites.GetFavoriteNavItems())
        {
            FavoriteItems.Add(item);
        }

        ThisPcItems.Clear();
        ThisPcItems.Add(new NexusNavItem
        {
            Id = NexusPaths.ThisPc,
            Label = "Denne PC",
            TargetPath = NexusPaths.ThisPc,
            IconPath = NexusLucideIcons.Computer,
            ShowPinToggle = false,
            Section = "Denne PC",
        });
        foreach (var drive in _fileSystem.ListLocation(NexusPaths.ThisPc))
        {
            ThisPcItems.Add(new NexusNavItem
            {
                Id = drive.FullPath,
                Label = drive.Name,
                TargetPath = drive.FullPath,
                IconPath = NexusLucideIcons.HardDrive,
                ShowPinToggle = false,
                IsIndented = true,
                Section = "Denne PC",
            });
        }

        NexusItems.Clear();
        NexusItems.Add(new NexusNavItem
        {
            Id = NexusPaths.Projects,
            Label = "Projekter",
            TargetPath = NexusPaths.Projects,
            IconPath = NexusLucideIcons.Briefcase,
            ShowPinToggle = false,
            Section = "Nexus",
        });
        NexusItems.Add(new NexusNavItem
        {
            Id = NexusPaths.Workspaces,
            Label = "Arbejdsområder",
            TargetPath = NexusPaths.Workspaces,
            IconPath = NexusLucideIcons.LayoutGrid,
            ShowPinToggle = false,
            Section = "Nexus",
        });
        NexusItems.Add(new NexusNavItem
        {
            Id = NexusPaths.Recent,
            Label = "Seneste",
            TargetPath = NexusPaths.Recent,
            IconPath = NexusLucideIcons.Clock,
            ShowPinToggle = false,
            Section = "Nexus",
        });
    }

    private void TogglePin(string? favoriteId)
    {
        if (string.IsNullOrWhiteSpace(favoriteId))
        {
            return;
        }

        _favorites.TogglePin(favoriteId);
    }

    private void OpenSelected()
    {
        if (SelectedItem is not null)
        {
            OpenItem(SelectedItem);
        }
    }

    public void SelectFile(string filePath)
    {
        var directory = Path.GetDirectoryName(filePath);
        if (string.IsNullOrWhiteSpace(directory))
        {
            return;
        }

        NavigateTo(directory, recordHistory: true);
        SelectedItem = Items.FirstOrDefault(item =>
            string.Equals(item.FullPath, filePath, StringComparison.OrdinalIgnoreCase));
    }

    private void OpenItem(FileSystemItem? item)
    {
        if (item is null)
        {
            return;
        }

        if (item.IsDirectory)
        {
            NavigateTo(item.FullPath);
            return;
        }

        var owner = System.Windows.Application.Current?.MainWindow;
        if (_fileOpen.TryOpenFile(item.FullPath, owner, out var error))
        {
            StatusMessage = $"Åbnede {item.Name} med Nexus";
            return;
        }

        StatusMessage = error ?? $"Kunne ikke åbne {item.Name}";
    }

    private void NotifyNavigationState()
    {
        OnPropertyChanged(nameof(CurrentPath));
        OnPropertyChanged(nameof(CanGoUp));
        OnPropertyChanged(nameof(CanGoBack));
        OnPropertyChanged(nameof(CanGoForward));
        System.Windows.Input.CommandManager.InvalidateRequerySuggested();
    }

    private void OnPropertyChanged([CallerMemberName] string? name = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
