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;

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

    [ObservableProperty]
    private string _searchQuery = string.Empty;

    [ObservableProperty]
    private bool _isConfigured;

    [ObservableProperty]
    private string _downloadStatus = string.Empty;

    private int _currentPage;

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

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

        IsConfigured = !string.IsNullOrWhiteSpace(url);

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

    [RelayCommand]
    public async Task LoadBooksAsync()
    {
        if (IsBusy || !IsConfigured) return;
        IsBusy = true;
        _currentPage = 0;

        try
        {
            var books = await _calibreWebService.GetBooksAsync(SearchQuery, _currentPage);
            Books.Clear();
            foreach (var book in books)
            {
                Books.Add(book);
            }
        }
        catch (Exception ex)
        {
            await Shell.Current.DisplayAlert("Error", $"Failed to load library: {ex.Message}", "OK");
        }
        finally
        {
            IsBusy = false;
        }
    }

    [RelayCommand]
    public async Task LoadMoreBooksAsync()
    {
        if (IsBusy || !IsConfigured) return;
        IsBusy = true;
        _currentPage++;

        try
        {
            var books = await _calibreWebService.GetBooksAsync(SearchQuery, _currentPage);
            foreach (var book in books)
            {
                Books.Add(book);
            }
        }
        catch { }
        finally
        {
            IsBusy = false;
        }
    }

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

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

        IsBusy = true;
        DownloadStatus = $"Downloading {calibreBook.Title}...";

        try
        {
            var progress = new Progress<double>(p =>
            {
                DownloadStatus = $"Downloading... {p * 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 = "Download complete!";
            await Shell.Current.DisplayAlert("Success", $"\"{calibreBook.Title}\" has been added to your library.", "OK");
        }
        catch (Exception ex)
        {
            await Shell.Current.DisplayAlert("Error", $"Failed to download: {ex.Message}", "OK");
        }
        finally
        {
            IsBusy = false;
            DownloadStatus = string.Empty;
        }
    }

    [RelayCommand]
    public async Task OpenSettingsAsync()
    {
        await Shell.Current.GoToAsync("settings");
    }
}