using BookReader.Models;
using System.IO.Compression;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using VersOne.Epub;

namespace BookReader.Services;

public class BookParserService : IBookParserService
{
    private readonly IDatabaseService _databaseService;
    private readonly string _booksDir;

    public BookParserService(IDatabaseService databaseService)
    {
        _databaseService = databaseService;
        _booksDir = Path.Combine(FileSystem.AppDataDirectory, "Books");
        Directory.CreateDirectory(_booksDir);
    }

    public string GetBooksDirectory() => _booksDir;

    public async Task<Book> ParseAndStoreBookAsync(string sourceFilePath, string originalFileName)
    {
        var extension = Path.GetExtension(originalFileName).ToLowerInvariant();
        var bookId = Guid.NewGuid().ToString();
        var destPath = Path.Combine(_booksDir, $"{bookId}{extension}");

        // Перемещаем файл вместо копирования для экономии памяти
        if (sourceFilePath != destPath)
        {
            try
            {
                File.Move(sourceFilePath, destPath, overwrite: true);
            }
            catch (IOException)
            {
                // Если перемещение не удалось (например, файл на внешнем носителе), копируем
                using var sourceStream = File.OpenRead(sourceFilePath);
                using var destStream = File.Create(destPath);
                await sourceStream.CopyToAsync(destStream);
            }
        }

        var book = new Book
        {
            FilePath = destPath,
            FileName = originalFileName,
            Format = extension.TrimStart('.'),
            DateAdded = DateTime.UtcNow,
            LastRead = DateTime.UtcNow
        };

        switch (extension)
        {
            case Constants.Files.EpubExtension:
                await ParseEpubMetadataAsync(book);
                break;
            case Constants.Files.Fb2Extension:
                await ParseFb2MetadataAsync(book);
                break;
            default:
                book.Title = Path.GetFileNameWithoutExtension(originalFileName);
                break;
        }

        if (string.IsNullOrWhiteSpace(book.Title))
            book.Title = Path.GetFileNameWithoutExtension(originalFileName);

        await _databaseService.SaveBookAsync(book);
        return book;
    }

    public Task<string> GetBookContentPathAsync(Book book)
    {
        return Task.FromResult(book.FilePath);
    }

    private async Task ParseEpubMetadataAsync(Book book)
    {
        try
        {
            var epubBook = await EpubReader.ReadBookAsync(book.FilePath);

            book.Title = epubBook.Title ?? "Unknown Title";
            book.Author = epubBook.Author ?? "Unknown Author";

            // Extract cover
            if (epubBook.CoverImage != null)
            {
                book.CoverImage = epubBook.CoverImage;
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"Error parsing EPUB: {ex.Message}");
            book.Title = Path.GetFileNameWithoutExtension(book.FileName);
            book.Author = "Unknown";
        }
    }

    private async Task ParseFb2MetadataAsync(Book book)
    {
        try
        {
            string xml;
            if (book.FilePath.EndsWith(Constants.Files.Fb2ZipExtension, StringComparison.OrdinalIgnoreCase))
            {
                using var zip = ZipFile.OpenRead(book.FilePath);
                var entry = zip.Entries.FirstOrDefault(e => e.Name.EndsWith(Constants.Files.Fb2Extension, StringComparison.OrdinalIgnoreCase));
                if (entry != null)
                {
                    using var stream = entry.Open();
                    using var reader = new StreamReader(stream);
                    xml = await reader.ReadToEndAsync();
                }
                else return;
            }
            else
            {
                xml = await File.ReadAllTextAsync(book.FilePath);
            }

            var doc = XDocument.Parse(xml);
            XNamespace fb = "http://www.gribuser.ru/xml/fictionbook/2.0";

            var titleInfo = doc.Descendants(fb + "title-info").FirstOrDefault();
            if (titleInfo != null)
            {
                // Title
                var bookTitle = titleInfo.Element(fb + "book-title")?.Value;
                book.Title = bookTitle ?? "Unknown Title";

                // Author
                var authorElement = titleInfo.Element(fb + "author");
                if (authorElement != null)
                {
                    var firstName = authorElement.Element(fb + "first-name")?.Value ?? "";
                    var lastName = authorElement.Element(fb + "last-name")?.Value ?? "";
                    var middleName = authorElement.Element(fb + "middle-name")?.Value ?? "";
                    book.Author = $"{firstName} {middleName} {lastName}".Trim();
                }

                // Cover
                var coverPage = titleInfo.Element(fb + "coverpage");
                if (coverPage != null)
                {
                    var imageElement = coverPage.Descendants().FirstOrDefault(e => e.Name.LocalName == "image");
                    if (imageElement != null)
                    {
                        XNamespace xlink = "http://www.w3.org/1999/xlink";
                        var href = imageElement.Attribute(xlink + "href")?.Value
                                   ?? imageElement.Attribute("href")?.Value;

                        if (href != null)
                        {
                            href = href.TrimStart('#');
                            var binary = doc.Descendants(fb + "binary")
                                .FirstOrDefault(b => b.Attribute("id")?.Value == href);

                            if (binary != null)
                            {
                                try
                                {
                                    book.CoverImage = Convert.FromBase64String(binary.Value.Trim());
                                }
                                catch { }
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"Error parsing FB2: {ex.Message}");
            book.Title = Path.GetFileNameWithoutExtension(book.FileName);
            book.Author = "Unknown";
        }
    }
}