using BookReader.Models;
using BookReader.Services;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;

namespace BookReader.ViewModels;

public partial class BookshelfViewModel : BaseViewModel
{
    private readonly IDatabaseService _databaseService;
    private readonly IBookParserService _bookParserService;
    private readonly INavigationService _navigationService;

    public ObservableCollection<Book> Books { get; } = new();

    [ObservableProperty]
    private bool _isEmpty;

    [ObservableProperty]
    private string _searchText = string.Empty;

    [ObservableProperty]
    private int _booksInProgress;

    [ObservableProperty]
    private int _completedBooks;

    [ObservableProperty]
    private Book? _continueReadingBook;

    public bool HasContinueReading => ContinueReadingBook != null;
    public string LibrarySummary => $"{Books.Count} книг в библиотеке";

    partial void OnSearchTextChanged(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            LoadBooksCommand.Execute(null);
        }
    }

    partial void OnContinueReadingBookChanged(Book? value)
    {
        OnPropertyChanged(nameof(HasContinueReading));
    }

    public BookshelfViewModel(
        IDatabaseService databaseService,
        IBookParserService bookParserService,
        INavigationService navigationService)
    {
        _databaseService = databaseService;
        _bookParserService = bookParserService;
        _navigationService = navigationService;
        Title = "Библиотека";
    }

    [RelayCommand]
    public async Task LoadBooksAsync()
    {
        IsBusy = true;

        try
        {
            var books = await _databaseService.GetAllBooksAsync();

            if (!string.IsNullOrWhiteSpace(SearchText))
            {
                var searchLower = SearchText.Trim().ToLowerInvariant();
                books = books.Where(book =>
                        book.Title.ToLowerInvariant().Contains(searchLower) ||
                        book.Author.ToLowerInvariant().Contains(searchLower))
                    .ToList();
            }

            Books.Clear();
            foreach (var book in books)
            {
                Books.Add(book);
            }

            RefreshLibraryState();
        }
        catch (Exception ex)
        {
            await _navigationService.DisplayAlertAsync("Ошибка", $"Не удалось загрузить библиотеку: {ex.Message}", "OK");
        }
        finally
        {
            IsBusy = false;
        }
    }

    [RelayCommand]
    public async Task SearchAsync(object? parameter)
    {
        var requestedText = parameter?.ToString() ?? SearchText;
        SearchText = requestedText ?? string.Empty;
        await LoadBooksAsync();
    }

    [RelayCommand]
    public async Task AddBookFromFileAsync()
    {
        try
        {
            var customFileTypes = new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
            {
                { DevicePlatform.Android, new[] { "application/epub+zip", "application/x-fictionbook+xml", "application/octet-stream", "*/*" } }
            });

            var result = await FilePicker.Default.PickAsync(new PickOptions
            {
                PickerTitle = "Выберите книгу",
                FileTypes = customFileTypes
            });

            if (result == null)
            {
                return;
            }

            var extension = Path.GetExtension(result.FileName).ToLowerInvariant();
            if (extension != Constants.Files.EpubExtension && extension != Constants.Files.Fb2Extension)
            {
                await _navigationService.DisplayAlertAsync("Формат не поддерживается", "Сейчас можно добавить только EPUB и FB2.", "OK");
                return;
            }

            IsBusy = true;
            StatusMessage = "Добавляю книгу...";

            using var sourceStream = await result.OpenReadAsync();
            var tempPath = Path.Combine(FileSystem.CacheDirectory, result.FileName);
            using (var tempFileStream = File.Create(tempPath))
            {
                await sourceStream.CopyToAsync(tempFileStream);
            }

            var book = await _bookParserService.ParseAndStoreBookAsync(tempPath, result.FileName);
            Books.Insert(0, book);
            RefreshLibraryState();

            try
            {
                File.Delete(tempPath);
            }
            catch
            {
            }
        }
        catch (Exception ex)
        {
            await _navigationService.DisplayAlertAsync("Ошибка", $"Не удалось добавить книгу: {ex.Message}", "OK");
        }
        finally
        {
            IsBusy = false;
            StatusMessage = string.Empty;
        }
    }

    [RelayCommand]
    public async Task DeleteBookAsync(Book book)
    {
        if (book == null)
        {
            return;
        }

        var confirmed = await _navigationService.DisplayAlertAsync(
            "Удалить книгу",
            $"Удалить \"{book.Title}\" из библиотеки?",
            "Удалить",
            "Отмена");

        if (!confirmed)
        {
            return;
        }

        try
        {
            await _databaseService.DeleteBookAsync(book);
            Books.Remove(book);
            RefreshLibraryState();
        }
        catch (Exception ex)
        {
            await _navigationService.DisplayAlertAsync("Ошибка", $"Не удалось удалить книгу: {ex.Message}", "OK");
        }
    }

    [RelayCommand]
    public async Task OpenBookAsync(Book book)
    {
        if (book == null)
        {
            return;
        }

        var navigationParameter = new Dictionary<string, object>
        {
            { "Book", book }
        };

        await _navigationService.GoToAsync("reader", navigationParameter);
    }

    [RelayCommand]
    public Task OpenSettingsAsync() => _navigationService.GoToAsync("//settings");

    [RelayCommand]
    public Task OpenCalibreLibraryAsync() => _navigationService.GoToAsync("//calibre");

    private void RefreshLibraryState()
    {
        IsEmpty = Books.Count == 0;
        BooksInProgress = Books.Count(book => book.ReadingProgress > 0 && book.ReadingProgress < 1);
        CompletedBooks = Books.Count(book => book.ReadingProgress >= 1);
        ContinueReadingBook = Books
            .OrderByDescending(book => book.LastRead)
            .FirstOrDefault(book => book.ReadingProgress > 0 && book.ReadingProgress < 1);

        OnPropertyChanged(nameof(LibrarySummary));
    }
}
