using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Platform.Storage;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MarkdownEditor.Constants;
using MarkdownEditor.Models;
using MarkdownEditor.Services;

namespace MarkdownEditor.ViewModels;

/// <summary>
/// Main view model for the application window.
/// Manages the collection of markdown document tabs and file operations.
/// </summary>
public partial class MainWindowViewModel : ViewModelBase
{
    [ObservableProperty]
    private ObservableCollection<MarkdownTabViewModel> _tabs = new();

    [ObservableProperty]
    private MarkdownTabViewModel? _selectedTab;

    [ObservableProperty]
    private bool _isDarkMode = true;

    [ObservableProperty]
    private string _textSize = "Small"; // Small, Medium, Large

    private readonly IPdfExportService _pdfExportService;
    private readonly ISessionService _sessionService;
    private bool _isRestoringSession = false;
    private readonly bool _hasInitialFile;

    /// <summary>
    /// Gets or sets the storage provider for file dialogs.
    /// Set by the view when the window is opened.
    /// </summary>
    public IStorageProvider? StorageProvider { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="MainWindowViewModel"/> class.
    /// </summary>
    /// <param name="pdfExportService">Optional PDF export service for dependency injection.</param>
    /// <param name="sessionService">Optional session service for dependency injection.</param>
    /// <param name="initialFilePath">Optional file path to open on startup (takes precedence over session restore).</param>
    public MainWindowViewModel(IPdfExportService? pdfExportService = null, ISessionService? sessionService = null, string? initialFilePath = null)
    {
        _pdfExportService = pdfExportService ?? new PdfExportService();
        _sessionService = sessionService ?? new SessionService();

        // Track if we have an initial file (takes precedence over session restore)
        _hasInitialFile = !string.IsNullOrEmpty(initialFilePath) && System.IO.File.Exists(initialFilePath);

        if (_hasInitialFile)
        {
            var newTab = new MarkdownTabViewModel();
            newTab.LoadFromFile(initialFilePath!);
            Tabs.Add(newTab);
            SelectedTab = newTab;
        }
        else
        {
            // Will restore session after StorageProvider is set
            // For now, add a default tab as fallback (will be replaced if session exists)
            AddNewTab();
        }
    }

    /// <summary>
    /// Creates and adds a new empty tab.
    /// </summary>
    [RelayCommand]
    private void AddNewTab()
    {
        var newTab = new MarkdownTabViewModel
        {
            Title = $"Tab {Tabs.Count + 1}"
        };
        Tabs.Add(newTab);
        SelectedTab = newTab;
    }

    /// <summary>
    /// Closes the specified tab.
    /// Maintains at least one open tab and updates selection appropriately.
    /// </summary>
    /// <param name="tab">The tab to close.</param>
    [RelayCommand]
    private void CloseTab(MarkdownTabViewModel tab)
    {
        if (tab == null)
        {
            return;
        }

        if (Tabs.Count > AppConstants.Layout.MinTabsToAllowClose)
        {
            var index = Tabs.IndexOf(tab);
            Tabs.Remove(tab);

            if (SelectedTab == tab)
            {
                SelectedTab = Tabs[Math.Max(0, index - 1)];
            }
        }
    }

    /// <summary>
    /// Opens a markdown file from disk in a new or existing tab.
    /// </summary>
    [RelayCommand]
    private async Task OpenFile()
    {
        if (StorageProvider == null)
        {
            return;
        }

        try
        {
            var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
            {
                Title = AppConstants.Messages.OpenFileDialogTitle,
                AllowMultiple = false,
                FileTypeFilter = new[]
                {
                    new FilePickerFileType(AppConstants.Files.MarkdownFileTypeName)
                    {
                        Patterns = new[] { AppConstants.Files.MarkdownExtension, AppConstants.Files.MarkdownExtensionAlt }
                    },
                    FilePickerFileTypes.TextPlain,
                    FilePickerFileTypes.All
                }
            });

            if (files.Count > 0)
            {
                var file = files[0];
                var path = file.Path.LocalPath;

                // Check if file is already open
                var existingTab = Tabs.FirstOrDefault(t => t.FilePath == path);
                if (existingTab != null)
                {
                    SelectedTab = existingTab;
                    return;
                }

                // Create new tab and load file
                var newTab = new MarkdownTabViewModel();
                newTab.LoadFromFile(path);
                Tabs.Add(newTab);
                SelectedTab = newTab;
            }
        }
        catch
        {
            // Error opening file - fail silently
        }
    }

    /// <summary>
    /// Saves the currently selected tab's document.
    /// Prompts for a file location if not previously saved.
    /// </summary>
    [RelayCommand]
    private async Task SaveFile()
    {
        if (SelectedTab == null || StorageProvider == null)
        {
            return;
        }

        try
        {
            if (string.IsNullOrEmpty(SelectedTab.FilePath))
            {
                await SaveFileAs();
            }
            else
            {
                SelectedTab.SaveToFile(SelectedTab.FilePath);
            }
        }
        catch
        {
            // Error saving file - fail silently
        }
    }

    /// <summary>
    /// Prompts the user to save the currently selected tab's document to a new location.
    /// </summary>
    [RelayCommand]
    private async Task SaveFileAs()
    {
        if (SelectedTab == null || StorageProvider == null)
        {
            return;
        }

        try
        {
            var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
            {
                Title = AppConstants.Messages.SaveFileDialogTitle,
                SuggestedFileName = string.IsNullOrEmpty(SelectedTab.FilePath)
                    ? AppConstants.Files.DefaultFileName
                    : System.IO.Path.GetFileName(SelectedTab.FilePath),
                FileTypeChoices = new[]
                {
                    new FilePickerFileType(AppConstants.Files.MarkdownFileTypeName)
                    {
                        Patterns = new[] { AppConstants.Files.MarkdownExtension, AppConstants.Files.MarkdownExtensionAlt }
                    },
                    FilePickerFileTypes.TextPlain
                }
            });

            if (file != null)
            {
                SelectedTab.SaveToFile(file.Path.LocalPath);
            }
        }
        catch
        {
            // Error saving file - fail silently
        }
    }

    /// <summary>
    /// Exports the currently selected tab's markdown content to PDF.
    /// </summary>
    [RelayCommand]
    private async Task ExportToPdf()
    {
        if (SelectedTab == null || StorageProvider == null)
        {
            return;
        }

        try
        {
            var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
            {
                Title = "Export to PDF",
                SuggestedFileName = string.IsNullOrEmpty(SelectedTab.FilePath)
                    ? "document.pdf"
                    : System.IO.Path.GetFileNameWithoutExtension(SelectedTab.FilePath) + ".pdf",
                FileTypeChoices = new[]
                {
                    new FilePickerFileType("PDF Document")
                    {
                        Patterns = new[] { "*.pdf" }
                    }
                }
            });

            if (file != null)
            {
                var title = string.IsNullOrEmpty(SelectedTab.Title)
                    ? "Markdown Document"
                    : SelectedTab.Title;

                await _pdfExportService.ExportToPdfAsync(
                    SelectedTab.MarkdownContent,
                    file.Path.LocalPath,
                    title);
            }
        }
        catch
        {
            // Error exporting to PDF - fail silently
        }
    }

    /// <summary>
    /// Toggles between dark and light mode.
    /// </summary>
    [RelayCommand]
    private void ToggleTheme()
    {
        IsDarkMode = !IsDarkMode;
    }

    /// <summary>
    /// Sets the text size to Small.
    /// </summary>
    [RelayCommand]
    private void SetTextSizeSmall()
    {
        TextSize = "Small";
    }

    /// <summary>
    /// Sets the text size to Medium.
    /// </summary>
    [RelayCommand]
    private void SetTextSizeMedium()
    {
        TextSize = "Medium";
    }

    /// <summary>
    /// Sets the text size to Large.
    /// </summary>
    [RelayCommand]
    private void SetTextSizeLarge()
    {
        TextSize = "Large";
    }

    // Computed properties for theme colors
    public string BackgroundColor => IsDarkMode ? "#1E1E1E" : "#FFFFFF";
    public string SecondaryBackgroundColor => IsDarkMode ? "#252526" : "#F3F3F3";
    public string TertiaryBackgroundColor => IsDarkMode ? "#2D2D2D" : "#E8E8E8";
    public string BorderColor => IsDarkMode ? "#3E3E42" : "#CCCCCC";
    public string ForegroundColor => IsDarkMode ? "#D4D4D4" : "#333333";
    public string SecondaryForegroundColor => IsDarkMode ? "#CCCCCC" : "#666666";
    public string ActiveBackgroundColor => IsDarkMode ? "#505050" : "#D0D0D0";
    public string HoverBackgroundColor => IsDarkMode ? "#3E3E42" : "#E0E0E0";
    public string LineNumberColor => IsDarkMode ? "#858585" : "#999999";

    // Computed properties for font sizes
    public double EditorFontSize => TextSize switch
    {
        "Small" => 14,
        "Medium" => 16,
        "Large" => 18,
        _ => 14
    };

    public double ContentFontSize => TextSize switch
    {
        "Small" => 14,
        "Medium" => 16,
        "Large" => 18,
        _ => 14
    };

    partial void OnIsDarkModeChanged(bool value)
    {
        // Notify all color properties have changed
        OnPropertyChanged(nameof(BackgroundColor));
        OnPropertyChanged(nameof(SecondaryBackgroundColor));
        OnPropertyChanged(nameof(TertiaryBackgroundColor));
        OnPropertyChanged(nameof(BorderColor));
        OnPropertyChanged(nameof(ForegroundColor));
        OnPropertyChanged(nameof(SecondaryForegroundColor));
        OnPropertyChanged(nameof(ActiveBackgroundColor));
        OnPropertyChanged(nameof(HoverBackgroundColor));
        OnPropertyChanged(nameof(LineNumberColor));
    }

    partial void OnTextSizeChanged(string value)
    {
        // Notify all font size properties have changed
        OnPropertyChanged(nameof(EditorFontSize));
        OnPropertyChanged(nameof(ContentFontSize));
    }

    /// <summary>
    /// Restores the previous session (open files and tabs).
    /// Should be called after StorageProvider is set.
    /// </summary>
    public async Task RestoreSessionAsync()
    {
        // Don't restore if we opened a specific file (command line argument)
        if (_hasInitialFile || _isRestoringSession)
        {
            return;
        }

        _isRestoringSession = true;

        try
        {
            var sessionData = await _sessionService.LoadSessionAsync();
            
            if (sessionData == null || sessionData.Tabs.Count == 0)
            {
                // No session to restore, keep the default tab
                return;
            }

            // Clear existing tabs
            Tabs.Clear();

            // Restore each tab from the session
            foreach (var sessionTab in sessionData.Tabs)
            {
                var tab = new MarkdownTabViewModel();

                if (!string.IsNullOrEmpty(sessionTab.FilePath) && System.IO.File.Exists(sessionTab.FilePath))
                {
                    // File exists
                    tab.FilePath = sessionTab.FilePath;
                    
                    if (sessionTab.IsDirty && !string.IsNullOrEmpty(sessionTab.Content))
                    {
                        // File was dirty - restore the unsaved content (don't load from disk)
                        tab.MarkdownContent = sessionTab.Content;
                        tab.IsDirty = true;
                        tab.Title = System.IO.Path.GetFileName(sessionTab.FilePath);
                    }
                    else
                    {
                        // File wasn't dirty - load from disk (may have been modified externally)
                        tab.LoadFromFile(sessionTab.FilePath);
                    }
                }
                else if (!string.IsNullOrEmpty(sessionTab.Content))
                {
                    // Unsaved file or file no longer exists - restore content
                    tab.MarkdownContent = sessionTab.Content;
                    tab.Title = string.IsNullOrEmpty(sessionTab.Title) 
                        ? AppConstants.Messages.DefaultTabTitle 
                        : sessionTab.Title;
                    tab.IsDirty = sessionTab.IsDirty;
                }
                else
                {
                    // Empty tab
                    tab.Title = string.IsNullOrEmpty(sessionTab.Title) 
                        ? AppConstants.Messages.DefaultTabTitle 
                        : sessionTab.Title;
                }

                Tabs.Add(tab);
            }

            // Restore selected tab
            if (sessionData.SelectedTabIndex >= 0 && sessionData.SelectedTabIndex < Tabs.Count)
            {
                SelectedTab = Tabs[sessionData.SelectedTabIndex];
            }
            else if (Tabs.Count > 0)
            {
                SelectedTab = Tabs[0];
            }
        }
        catch
        {
            // If restoration fails, keep the default tab
        }
        finally
        {
            _isRestoringSession = false;
        }
    }

    /// <summary>
    /// Saves the current session state (open files and tabs).
    /// Should be called when the window is closing.
    /// </summary>
    public async Task SaveSessionAsync()
    {
        try
        {
            var sessionTabs = Tabs.Select(tab => new SessionTabInfo
            {
                FilePath = tab.FilePath,
                Content = tab.MarkdownContent,
                Title = tab.Title,
                IsDirty = tab.IsDirty
            }).ToList();

            var selectedIndex = SelectedTab != null ? Tabs.IndexOf(SelectedTab) : 0;
            if (selectedIndex < 0)
            {
                selectedIndex = 0;
            }

            await _sessionService.SaveSessionAsync(sessionTabs, selectedIndex);
        }
        catch
        {
            // Fail silently - session saving is a convenience feature
        }
    }

    /// <summary>
    /// Checks if there are any tabs with unsaved changes.
    /// </summary>
    /// <returns>True if any tab has unsaved changes, false otherwise.</returns>
    public bool HasUnsavedChanges()
    {
        return Tabs.Any(tab => tab.IsDirty);
    }

    /// <summary>
    /// Gets the count of tabs with unsaved changes.
    /// </summary>
    /// <returns>The number of tabs with unsaved changes.</returns>
    public int GetUnsavedChangesCount()
    {
        return Tabs.Count(tab => tab.IsDirty);
    }

    /// <summary>
    /// Saves all tabs with unsaved changes.
    /// Prompts for file location for unsaved files without a path.
    /// </summary>
    /// <returns>True if all files were saved successfully, false if user cancelled or error occurred.</returns>
    public async Task<bool> SaveAllUnsavedChangesAsync()
    {
        if (StorageProvider == null)
        {
            return false;
        }

        var dirtyTabs = Tabs.Where(tab => tab.IsDirty).ToList();

        foreach (var tab in dirtyTabs)
        {
            try
            {
                if (string.IsNullOrEmpty(tab.FilePath))
                {
                    // File hasn't been saved yet - prompt for location
                    var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
                    {
                        Title = AppConstants.Messages.SaveFileDialogTitle,
                        SuggestedFileName = AppConstants.Files.DefaultFileName,
                        FileTypeChoices = new[]
                        {
                            new FilePickerFileType(AppConstants.Files.MarkdownFileTypeName)
                            {
                                Patterns = new[] { AppConstants.Files.MarkdownExtension, AppConstants.Files.MarkdownExtensionAlt }
                            },
                            FilePickerFileTypes.TextPlain
                        }
                    });

                    if (file == null)
                    {
                        // User cancelled - stop saving
                        return false;
                    }

                    tab.SaveToFile(file.Path.LocalPath);
                }
                else
                {
                    // File has a path - save directly
                    tab.SaveToFile(tab.FilePath);
                }
            }
            catch
            {
                // Continue with other files even if one fails
            }
        }

        return true;
    }
}
