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

namespace BookReader.ViewModels;

public partial class CalibreLibraryViewModel : BaseViewModel
{
    private readonly ICalibreWebService _calibreWebService;
    private readonly IBookParserService _bookParserService;
    private readonly IDatabaseService _databaseService;
    private readonly ISettingsService _settingsService;
    private readonly INavigationService _navigationService;

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

    [ObservableProperty]
    private string _searchQuery = string.Empty;

    [ObservableProperty]
    private bool _isConfigured;

    [ObservableProperty]
    private string _downloadStatus = string.Empty;

    [ObservableProperty]
    private bool _isRefreshing;

    [ObservableProperty]
    private string _connectionErrorMessage = string.Empty;

    private int _currentPage;

    public bool HasConnectionError => !string.IsNullOrWhiteSpace(ConnectionErrorMessage);
    public bool HasBooks => Books.Count > 0;

    partial void OnConnectionErrorMessageChanged(string value)
    {
        OnPropertyChanged(nameof(HasConnectionError));
    }

    public CalibreLibraryViewModel(
        ICalibreWebService calibreWebService,
        IBookParserService bookParserService,
        IDatabaseService databaseService,
        ISettingsService settingsService,
        INavigationService navigationService)
    {
        _calibreWebService = calibreWebService;
        _bookParserService = bookParserService;
        _databaseService = databaseService;
        _settingsService = settingsService;
        _navigationService = navigationService;
        Title = "Calibre";
    }

    [RelayCommand]
    public async Task InitializeAsync()
    {
        var url = await _settingsService.GetAsync(SettingsKeys.CalibreUrl);
        var username = await _settingsService.GetAsync(SettingsKeys.CalibreUsername);
        var password = await _settingsService.GetSecurePasswordAsync();

        IsConfigured = !string.IsNullOrWhiteSpace(url);
        ConnectionErrorMessage = string.Empty;

        if (IsConfigured)
        {
            _calibreWebService.Configure(url, username, password);
            await LoadBooksAsync();
        }
        else
        {
            Books.Clear();
        }
    }

    [RelayCommand]
    public async Task LoadBooksAsync()
    {
        if (IsBusy || !IsConfigured)
        {
            return;
        }

        IsBusy = true;
        _currentPage = 0;
        ConnectionErrorMessage = string.Empty;

        try
        {
            var result = await _calibreWebService.GetBooksAsync(SearchQuery, _currentPage);
            if (!result.IsSuccess)
            {
                Books.Clear();
                ConnectionErrorMessage = result.ErrorMessage ?? "Не удалось загрузить каталог Calibre.";
                return;
            }

            ReplaceBooks(result.Value ?? new List<CalibreBook>());
        }
        finally
        {
            IsBusy = false;
        }
    }

    [RelayCommand]
    public async Task RefreshBooksAsync()
    {
        if (IsRefreshing || !IsConfigured)
        {
            return;
        }

        IsRefreshing = true;

        try
        {
            await LoadBooksAsync();
        }
        finally
        {
            IsRefreshing = false;
        }
    }

    [RelayCommand]
    public async Task LoadMoreBooksAsync()
    {
        if (IsBusy || !IsConfigured || HasConnectionError)
        {
            return;
        }

        IsBusy = true;
        _currentPage++;

        try
        {
            var result = await _calibreWebService.GetBooksAsync(SearchQuery, _currentPage);
            if (!result.IsSuccess)
            {
                DownloadStatus = result.ErrorMessage ?? "Не удалось подгрузить ещё книги.";
                return;
            }

            var existingIds = Books.Select(book => book.Id).ToHashSet();
            foreach (var book in result.Value ?? new List<CalibreBook>())
            {
                if (existingIds.Add(book.Id))
                {
                    Books.Add(book);
                }
            }
        }
        finally
        {
            IsBusy = false;
        }
    }

    [RelayCommand]
    public async Task SearchAsync()
    {
        await LoadBooksAsync();
    }

    [RelayCommand]
    public async Task DownloadBookAsync(CalibreBook calibreBook)
    {
        if (calibreBook == null)
        {
            return;
        }

        IsBusy = true;
        DownloadStatus = $"Загрузка: {calibreBook.Title}";

        try
        {
            var progress = new Progress<double>(value =>
            {
                DownloadStatus = $"Загрузка: {value * 100:F0}%";
            });

            var filePath = await _calibreWebService.DownloadBookAsync(calibreBook, progress);
            var fileName = $"{calibreBook.Title}.{calibreBook.Format}";

            var book = await _bookParserService.ParseAndStoreBookAsync(filePath, fileName);
            book.CalibreId = calibreBook.Id;

            if (calibreBook.CoverImage != null)
            {
                book.CoverImage = calibreBook.CoverImage;
            }

            await _databaseService.UpdateBookAsync(book);

            DownloadStatus = "Книга добавлена в библиотеку";
            await _navigationService.DisplayAlertAsync("Готово", $"\"{calibreBook.Title}\" добавлена в библиотеку.", "OK");
        }
        catch (Exception ex)
        {
            await _navigationService.DisplayAlertAsync("Ошибка", $"Не удалось скачать книгу: {ex.Message}", "OK");
        }
        finally
        {
            IsBusy = false;
        }
    }

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

    private void ReplaceBooks(IEnumerable<CalibreBook> books)
    {
        Books.Clear();
        foreach (var book in books)
        {
            Books.Add(book);
        }

        OnPropertyChanged(nameof(HasBooks));
    }
}
