using System.Globalization;
using System.Text.RegularExpressions;
using ExcelTableImporter.Models.ExcelModels;
using ExcelTableImporter.Models.ExcelModels.ExcelModels;
using NPOI.SS.UserModel;

namespace ExcelTableImporter;

public class LibrayLoader
{
    public async Task<AnimeLibrary> LoadLibrary(string filePath)
    {
        var animeRows = await ReadExcelFile(filePath);
        return MakeLibrary(animeRows);
    }

    private async Task<List<AnimeRow>> ReadExcelFile(string filePath)
    {
        await using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        IWorkbook workbook = WorkbookFactory.Create(stream);
        var sheet = workbook.GetSheetAt(0);

        var animeRows = new List<AnimeRow>();
        for (var i = 1; i <= sheet.LastRowNum; i++)
        {
            var row = sheet.GetRow(i);
            var isEmpty = row.GetCell(0) is null
                          && row.GetCell(1) is null
                          && row.GetCell(2) is null
                          && row.GetCell(3) is null
                          && row.GetCell(4) is null
                          && row.GetCell(8) is null
                          && row.GetCell(9) is null;
    
            if (isEmpty) continue;
            var c1 = row.GetCell(0)?.ToString(); // russian name
            var c2 = row.GetCell(1)?.ToString(); // original name
            var c3 = TryShort(row.GetCell(2)); // release year
            var c4 = ReadSerialsCount(row.GetCell(3)); // formula cell
            var c5 = ReadSerialsCount(row.GetCell(4)); // series viewed
            var c6 = row.GetCell(6)?.ToString(); // is completed
            var c7 = TryShort(row.GetCell(8)); // rating
            var c8 = row.GetCell(9)?.ToString(); // comment
            // var str = $"{c1} | {c2} [{c3}] - {c4} - : — {c5} — [{c6}] [{c7}]; {c8}";
    
            animeRows.Add(new AnimeRow
            {
                NameRussian = c1,
                NameOriginal = c2,
                ReleaseYear = c3,
                AnimeSeriesCountItems = ParseFormula(c4),
                AnimeSeriesViewsCountItems = ParseFormula(c5),
                IsCompleted = c6 == "Да",
                RatingValue = c7,
                Comment = c8,
            });
            // Console.WriteLine(str);
        }

        return animeRows;
    }

    private AnimeLibrary MakeLibrary(List<AnimeRow> animeRows)
    {
        var animeTitles = new Dictionary<string, AnimeTitle>(StringComparer.OrdinalIgnoreCase);

        foreach (var row in animeRows)
        {
            if (!animeTitles.TryGetValue(row.NameOriginal, out var title))
            {
                title = new AnimeTitle
                {
                    NameRussian = row.NameRussian,
                    NameOriginal = row.NameOriginal,
                    ReleaseYear = row.ReleaseYear,
                    RatingValue = row.RatingValue,
                    Comment = row.Comment
                };

                animeTitles[row.NameOriginal] = title;
            }

            var part = new AnimePart
            {
                ReleaseYear = row.ReleaseYear,
                Type = DetectPartType(row.NameRussian, row.NameOriginal),
                SeasonNumber = DetectSeasonNumber(row.NameRussian)
            };

            foreach (var item in row.AnimeSeriesCountItems)
            {
                part.EpisodeGroups.Add(new AnimeEpisodeGroup
                {
                    Order = item.Order,
                    Count = item.Count,
                    Viewed = row.AnimeSeriesViewsCountItems
                        .FirstOrDefault(v => v.Order == item.Order)?.Count ?? 0
                });
            }

            title.Parts.Add(part);
        }

        return new AnimeLibrary
        {
            Titles = animeTitles.Values.ToList()
        };
    }
    
    static short? TryShort(ICell? cell)
    {
        if (cell == null) return null;
        if (cell.CellType == CellType.Numeric) return Convert.ToInt16(cell.NumericCellValue);
        if (short.TryParse(cell.ToString(), out var v)) return v;
        return null;
    }

    static string? ReadSerialsCount(ICell? cell)
    {
        if (cell == null) return null;
        return cell.CellType switch
        {
            CellType.Numeric => cell.NumericCellValue.ToString(CultureInfo.InvariantCulture),
            CellType.Formula => cell.CellFormula,
            _ => null
        };
    }
    
    static List<AnimeSeriesCountItem> ParseFormula(string? formula)
    {
        var result = new List<AnimeSeriesCountItem>();
        if (string.IsNullOrWhiteSpace(formula)) return result;
        formula = formula.TrimStart('=');

        var parts = formula.Split('+', StringSplitOptions.RemoveEmptyEntries);

        var order = 1;
        foreach (var p in parts)
        {
            if (int.TryParse(p, out var count))
            {
                result.Add(new AnimeSeriesCountItem
                {
                    Order = order++,
                    Count = count
                });
            }
        }

        return result;
    }
    
    static AnimePartType DetectPartType(string nameRu, string nameOrig)
    {
        var name = (nameRu + " " + nameOrig).ToLowerInvariant();

        if (name.Contains("фильм") || name.Contains("movie") || name.Contains("gekijouban"))
            return AnimePartType.Movie;

        if (name.Contains("ova"))
            return AnimePartType.Ova;

        if (name.Contains("special") || name.Contains("спешл"))
            return AnimePartType.Special;

        return AnimePartType.Season;
    }

    static int? DetectSeasonNumber(string nameRu)
    {
        var match = Regex.Match(nameRu, @"сезон\s*(\d+)", RegexOptions.IgnoreCase);
        if (match.Success && int.TryParse(match.Groups[1].Value, out var num))
            return num;

        return null;
    }
}