using System.IO;
using System.Linq;
using Kavita.API.Services;
using Kavita.Models.Entities.Enums;
using Kavita.Models.Metadata;
using Kavita.Models.Parser;

namespace Kavita.Services.Scanner;
#nullable enable

/// <summary>
/// Responsible for Parsing ComicVine Comics.
/// </summary>
/// <param name="directoryService"></param>
public class ComicVineParser(IDirectoryService directoryService) : DefaultParser(directoryService)
{
    /// <summary>
    /// This Parser generates Series name to be defined as Series + first Issue Volume, so "Batman (2020)".
    /// </summary>
    /// <param name="filePath"></param>
    /// <param name="rootPath"></param>
    /// <param name="libraryRoot"></param>
    /// <param name="type"></param>
    /// <param name="enableMetadata"></param>
    /// <param name="comicInfo"></param>
    /// <returns></returns>
    public override ParserInfo? Parse(string filePath, string rootPath, string libraryRoot, LibraryType type, bool enableMetadata = true, ComicInfo? comicInfo = null)
    {
        if (type != LibraryType.ComicVine) return null;

        var fileName = directoryService.FileSystem.Path.GetFileNameWithoutExtension(filePath);
        // Mylar often outputs cover.jpg, ignore it by default
        if (string.IsNullOrEmpty(fileName) || Parser.IsCoverImage(directoryService.FileSystem.Path.GetFileName(filePath))) return null;

        var directoryName = directoryService.FileSystem.DirectoryInfo.New(rootPath).Name;

        var info = new ParserInfo()
        {
            Filename = Path.GetFileName(filePath),
            Format = Parser.ParseFormat(filePath),
            Title = Parser.RemoveExtensionIfSupported(fileName)!,
            FullFilePath = Parser.NormalizePath(filePath),
            Series = string.Empty,
            ComicInfo = comicInfo,
            Chapters = Parser.ParseChapter(fileName, type),
            Volumes = Parser.ParseVolume(fileName, type),
            HasEndMarker = Parser.HasEndMarker(fileName)
        };

        ParseExternalIdsFromNotesAndWeblinks(info);

        // See if we can formulate the name from the ComicInfo
        if (!string.IsNullOrEmpty(info.ComicInfo?.Series) && !string.IsNullOrEmpty(info.ComicInfo?.Volume))
        {
            info.Series = $"{info.ComicInfo.Series} ({info.ComicInfo.Volume})";
        }

        if (string.IsNullOrEmpty(info.Series))
        {
            // Check if we need to fallback to the Folder name AND that the folder matches the format "Series (Year)"
            var directories = directoryService.GetFoldersTillRoot(rootPath, filePath).ToList();
            if (directories.Count > 0)
            {
                foreach (var directory in directories)
                {
                    if (!Parser.IsSeriesAndYear(directory)) continue;
                    info.Series = directory;
                    info.Volumes = Parser.ParseYear(directory);
                    break;
                }

                // When there was at least one directory and we failed to parse the series, this is the final fallback
                if (string.IsNullOrEmpty(info.Series))
                {
                    info.Series = Parser.CleanTitle(directories[0], true);
                }
            }
            else
            {
                if (Parser.IsSeriesAndYear(directoryName))
                {
                    info.Series = directoryName;
                    info.Volumes = Parser.ParseYear(directoryName);
                }
            }
        }

        // Check if this is a Special/Annual
        info.IsSpecial = Parser.IsSpecial(info.Filename, type) || Parser.IsSpecial(info.ComicInfo?.Format, type);

        // Patch in other information from ComicInfo
        if (enableMetadata)
        {
            UpdateFromComicInfo(info);
        }

        if (string.IsNullOrEmpty(info.Series))
        {
            info.Series = Parser.CleanTitle(directoryName, true);
        }

        FinalizeNumbers(info);
        return string.IsNullOrEmpty(info.Series) ? null : info;
    }

    /// <summary>
    /// Only applicable for ComicVine library type
    /// </summary>
    /// <param name="filePath"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    public override bool IsApplicable(string filePath, LibraryType type)
    {
        return type == LibraryType.ComicVine;
    }

    private new static void UpdateFromComicInfo(ParserInfo info)
    {
        if (info.ComicInfo == null) return;

        if (!string.IsNullOrEmpty(info.ComicInfo.Volume))
        {
            info.Volumes = info.ComicInfo.Volume;
        }
        if (string.IsNullOrEmpty(info.LocalizedSeries) && !string.IsNullOrEmpty(info.ComicInfo.LocalizedSeries))
        {
            info.LocalizedSeries = info.ComicInfo.LocalizedSeries.Trim();
        }
        if (!string.IsNullOrEmpty(info.ComicInfo.Number))
        {
            info.Chapters = info.ComicInfo.Number;
            if (info.IsSpecial && !Parser.IsDefaultChapter(info.Chapters))
            {
                info.IsSpecial = false;
                info.Volumes = $"{Parser.SpecialVolumeNumber}";
            }
        }

        // Patch is SeriesSort from ComicInfo
        if (!string.IsNullOrEmpty(info.ComicInfo.TitleSort))
        {
            info.SeriesSort = info.ComicInfo.TitleSort.Trim();
        }
    }
}
