using MangaReader.Core.HttpService;
using MangaReader.Core.Sources.MangaDex.Api;
using MangaReader.Tests.Utilities;
using NSubstitute;
using Shouldly;

namespace MangaReader.Tests.Sources.MangaDex.Api;

public class MangaDexClientTests
{
    [Fact]
    public async Task Search_Manga()
    {
        string searchResultJson = await ReadJsonResourceAsync("Manga-Search-Response.json");

        IHttpService httpService = Substitute.For<IHttpService>();

        httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
            .Returns(Task.FromResult(searchResultJson));

        MangaDexClient mangaDexClient = new(httpService);
        MangaDexResponse? mangaDexResponse = await mangaDexClient.SearchMangaByTitleAsync("Some random text", CancellationToken.None);

        // Testing here
        mangaDexResponse.ShouldNotBeNull();
        mangaDexResponse.Response.ShouldBe("collection");
        mangaDexResponse.ShouldBeOfType<MangaDexCollectionResponse>();

        MangaDexCollectionResponse mangaDexCollectionResponse = (mangaDexResponse as MangaDexCollectionResponse)!;
        mangaDexCollectionResponse.Data.Count.ShouldBe(3);

        mangaDexCollectionResponse.Data[0].ShouldBeOfType<MangaEntity>();
        MangaEntity mangaEntity = (mangaDexCollectionResponse.Data[0] as MangaEntity)!;

        mangaEntity.Attributes.ShouldNotBeNull();

        mangaEntity.Attributes.Title.ShouldContainKey("en");
        mangaEntity.Attributes.Title["en"].ShouldBe("Gals Can’t Be Kind to Otaku!?");

        mangaEntity.Attributes.Description.ShouldContainKey("en");
        mangaEntity.Attributes.Description["en"].ShouldBe("Takuya Seo is an otaku who likes \"anime for girls\" and can't say he likes it out loud. One day, he hooks up with two gals from his class, Amane and Ijichi, but it seems that Amane is also an otaku...");

        mangaEntity.Attributes.Tags.Count.ShouldBe(5);

        mangaEntity.Attributes.Tags[0].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[0].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[0].Attributes!.Name["en"].ShouldBe("Romance");

        mangaEntity.Attributes.Tags[1].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[1].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[1].Attributes!.Name["en"].ShouldBe("Comedy");

        mangaEntity.Attributes.Tags[2].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[2].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[2].Attributes!.Name["en"].ShouldBe("School Life");

        mangaEntity.Attributes.Tags[3].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[3].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[3].Attributes!.Name["en"].ShouldBe("Slice of Life");

        mangaEntity.Attributes.Tags[4].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[4].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[4].Attributes!.Name["en"].ShouldBe("Gyaru");

        mangaEntity.Relationships.Count.ShouldBe(4);
        mangaEntity.Relationships[2].ShouldBeOfType<CoverArtEntity>();

        CoverArtEntity coverArtEntity = (mangaEntity.Relationships[2] as CoverArtEntity)!;
        coverArtEntity.Attributes.ShouldNotBeNull();
        coverArtEntity.Attributes.FileName.ShouldBe("6b3073de-bb65-4723-8113-6068bf8c6eb4.jpg");
    }

    [Fact]
    public async Task Search_Manga_2()
    {
        string searchResultJson = await ReadJsonResourceAsync("Manga-Search-Response-2.json");

        IHttpService httpService = Substitute.For<IHttpService>();

        httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
            .Returns(Task.FromResult(searchResultJson));

        MangaDexClient mangaDexClient = new(httpService);
        MangaDexResponse? mangaDexResponse = await mangaDexClient.SearchMangaByTitleAsync("Some random text", CancellationToken.None);

        // Testing here
        mangaDexResponse.ShouldNotBeNull();
        mangaDexResponse.Response.ShouldBe("collection");
        mangaDexResponse.ShouldBeOfType<MangaDexCollectionResponse>();

        MangaDexCollectionResponse mangaDexCollectionResponse = (mangaDexResponse as MangaDexCollectionResponse)!;
        mangaDexCollectionResponse.Data.Count.ShouldBe(5);

        mangaDexCollectionResponse.Data[3].ShouldBeOfType<MangaEntity>();
        MangaEntity mangaEntity = (mangaDexCollectionResponse.Data[3] as MangaEntity)!;

        mangaEntity.Attributes.ShouldNotBeNull();

        mangaEntity.Attributes.Title.ShouldContainKey("en");
        mangaEntity.Attributes.Title["en"].ShouldBe("Gal Yome no Himitsu");

        mangaEntity.Attributes.Description.ShouldContainKey("en");
        mangaEntity.Attributes.Description["en"].ShouldBe("Fuyuki is a beautiful and cool gal! But there's a secret side of her that she only shows in front of her husband...?");

        mangaEntity.Attributes.Tags.Count.ShouldBe(5);

        //mangaEntity.Attributes.Tags[0].Attributes.ShouldNotBeNull();
        //mangaEntity.Attributes.Tags[0].Attributes!.Name.ShouldContainKey("en");
        //mangaEntity.Attributes.Tags[0].Attributes!.Name["en"].ShouldBe("Romance");

        //mangaEntity.Attributes.Tags[1].Attributes.ShouldNotBeNull();
        //mangaEntity.Attributes.Tags[1].Attributes!.Name.ShouldContainKey("en");
        //mangaEntity.Attributes.Tags[1].Attributes!.Name["en"].ShouldBe("Comedy");

        //mangaEntity.Attributes.Tags[2].Attributes.ShouldNotBeNull();
        //mangaEntity.Attributes.Tags[2].Attributes!.Name.ShouldContainKey("en");
        //mangaEntity.Attributes.Tags[2].Attributes!.Name["en"].ShouldBe("School Life");

        //mangaEntity.Attributes.Tags[3].Attributes.ShouldNotBeNull();
        //mangaEntity.Attributes.Tags[3].Attributes!.Name.ShouldContainKey("en");
        //mangaEntity.Attributes.Tags[3].Attributes!.Name["en"].ShouldBe("Slice of Life");

        //mangaEntity.Attributes.Tags[4].Attributes.ShouldNotBeNull();
        //mangaEntity.Attributes.Tags[4].Attributes!.Name.ShouldContainKey("en");
        //mangaEntity.Attributes.Tags[4].Attributes!.Name["en"].ShouldBe("Gyaru");

        mangaEntity.Relationships.Count.ShouldBe(4);
        mangaEntity.Relationships[2].ShouldBeOfType<CoverArtEntity>();

        CoverArtEntity coverArtEntity = (mangaEntity.Relationships[2] as CoverArtEntity)!;
        coverArtEntity.Attributes.ShouldNotBeNull();
        coverArtEntity.Attributes.FileName.ShouldBe("07d02b26-cbd0-4323-8774-9d83579863d5.jpg");
    }

    [Fact]
    public async Task Get_Manga_Metadata()
    {
        string searchResultJson = await ReadJsonResourceAsync("Manga-Response.json");

        IHttpService httpService = Substitute.For<IHttpService>();

        httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
            .Returns(Task.FromResult(searchResultJson));

        MangaDexClient mangaDexClient = new(httpService);
        MangaDexResponse? mangaDexResponse = await mangaDexClient.GetMangaAsync(Guid.NewGuid(), CancellationToken.None);

        mangaDexResponse.ShouldNotBeNull();
        mangaDexResponse.Response.ShouldBe("entity");
        mangaDexResponse.ShouldBeOfType<MangaDexEntityResponse>();

        MangaDexEntityResponse? mangaDexEntityResponse = mangaDexResponse as MangaDexEntityResponse;
        mangaDexEntityResponse.ShouldNotBeNull();
        mangaDexEntityResponse.Data.ShouldNotBeNull();
        mangaDexEntityResponse.Data.ShouldBeOfType<MangaEntity>();

        MangaEntity? mangaEntity = mangaDexEntityResponse.Data as MangaEntity;
        mangaEntity.ShouldNotBeNull();

        mangaEntity.Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Title.ShouldContainKey("en");
        mangaEntity.Attributes.Title["en"].ShouldBe("Gals Can’t Be Kind to Otaku!?");
        
        mangaEntity.Attributes.Description.ShouldContainKey("en");
        mangaEntity.Attributes.Description["en"].ShouldBe("Takuya Seo is an otaku who likes \"anime for girls\" and can't say he likes it out loud. One day, he hooks up with two gals from his class, Amane and Ijichi, but it seems that Amane is also an otaku...");
        
        mangaEntity.Attributes.Tags.Count.ShouldBe(5);

        mangaEntity.Attributes.Tags[0].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[0].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[0].Attributes!.Name["en"].ShouldBe("Romance");

        mangaEntity.Attributes.Tags[1].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[1].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[1].Attributes!.Name["en"].ShouldBe("Comedy");

        mangaEntity.Attributes.Tags[2].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[2].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[2].Attributes!.Name["en"].ShouldBe("School Life");

        mangaEntity.Attributes.Tags[3].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[3].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[3].Attributes!.Name["en"].ShouldBe("Slice of Life");

        mangaEntity.Attributes.Tags[4].Attributes.ShouldNotBeNull();
        mangaEntity.Attributes.Tags[4].Attributes!.Name.ShouldContainKey("en");
        mangaEntity.Attributes.Tags[4].Attributes!.Name["en"].ShouldBe("Gyaru");

        mangaEntity.Relationships.Count.ShouldBe(4);
        mangaEntity.Relationships[0].ShouldBeOfType<AuthorEntity>();
        mangaEntity.Relationships[1].ShouldBeOfType<ArtistEntity>();
        mangaEntity.Relationships[2].ShouldBeOfType<CoverArtEntity>();
        mangaEntity.Relationships[3].ShouldBeOfType<CreatorEntity>();

        AuthorEntity authorEntity = (mangaEntity.Relationships[0] as AuthorEntity)!;
        authorEntity.Attributes.ShouldNotBeNull();
        authorEntity.Attributes.Name.ShouldBe("Norishiro-chan");

        ArtistEntity artistEntity = (mangaEntity.Relationships[1] as ArtistEntity)!;
        artistEntity.Attributes.ShouldNotBeNull();
        artistEntity.Attributes.Name.ShouldBe("Sakana Uozimi");

        CoverArtEntity coverArtEntity = (mangaEntity.Relationships[2] as CoverArtEntity)!;
        coverArtEntity.Attributes.ShouldNotBeNull();
        coverArtEntity.Attributes.FileName.ShouldBe("6b3073de-bb65-4723-8113-6068bf8c6eb4.jpg");
    }

    [Fact]
    public async Task Get_Manga_Feed()
    {
        string searchResultJson = await ReadJsonResourceAsync("Manga-Feed-Response.json");

        IHttpService httpService = Substitute.For<IHttpService>();

        httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
            .Returns(Task.FromResult(searchResultJson));

        MangaDexClient mangaDexClient = new(httpService);
        MangaDexResponse? mangaDexResponse = await mangaDexClient.GetFeedAsync(Guid.NewGuid(), CancellationToken.None);

        mangaDexResponse.ShouldNotBeNull();
        mangaDexResponse.Response.ShouldBe("collection");
        mangaDexResponse.ShouldBeOfType<MangaDexCollectionResponse>();

        MangaDexCollectionResponse mangaDexEntityResponse = (mangaDexResponse as MangaDexCollectionResponse)!;

        List<ChapterEntity> chapterEntities = [.. mangaDexEntityResponse.Data.FindAll(entity => entity is ChapterEntity).Cast<ChapterEntity>()];
        chapterEntities.Count.ShouldBe(82);

        chapterEntities[0].Attributes.ShouldNotBeNull();
        chapterEntities[0].Attributes!.Volume.ShouldBeNull();
        chapterEntities[0].Attributes!.Chapter.ShouldBe("69");
        chapterEntities[0].Attributes!.Title.ShouldBe("Otaku & Gyaru & Playing Couple");

        chapterEntities[1].Attributes.ShouldNotBeNull();
        chapterEntities[1].Attributes!.Volume.ShouldBe("9");
        chapterEntities[1].Attributes!.Chapter.ShouldBe("68");
        chapterEntities[1].Attributes!.Title.ShouldBe("Otaku & Gyaru & A Couple Date");
    }

    [Fact]
    public async Task Get_Chapters()
    {
        string searchResultJson = await ReadJsonResourceAsync("Manga-Chapter-Response.json");

        IHttpService httpService = Substitute.For<IHttpService>();

        httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
            .Returns(Task.FromResult(searchResultJson));

        MangaDexClient mangaDexClient = new(httpService);
        MangaDexChapterResponse? mangaDexChapterResponse = await mangaDexClient.GetChapterAsync(Guid.NewGuid(), CancellationToken.None);

        mangaDexChapterResponse.ShouldNotBeNull();
        mangaDexChapterResponse.Chapter.ShouldNotBeNull();
        mangaDexChapterResponse.Chapter.Hash.ShouldBe("f867bd09bc8b19a37cf5486134acdda1");
        mangaDexChapterResponse.Chapter.Data.Count.ShouldBe(13);
        mangaDexChapterResponse.Chapter.Data[0].ShouldBe("1-5ae1738e10f5440a74f11832cf6203be5bd938f72d5a80d42cd149ee21287901.png");
        mangaDexChapterResponse.Chapter.Data[12].ShouldBe("13-b6b8e15b5abd7e53af32cbfa1ac6dc1cb48fb314f2b5bb7412c9e393cf78224e.png");
        mangaDexChapterResponse.Chapter.DataSaver.Count.ShouldBe(13);
        mangaDexChapterResponse.Chapter.DataSaver[0].ShouldBe("1-7b0a40f35edd75f14d0aa9c0369f8bb05e41687165d97368b572f3c3c5b3db31.jpg");
        mangaDexChapterResponse.Chapter.DataSaver[12].ShouldBe("13-b886b4ed986a473478e3db7bb18fe2faea567a1ad5e520408967410dcf8838d1.jpg");
    }

    [Fact]
    public async Task Get_Cover_Art()
    {
        string searchResultJson = await ReadJsonResourceAsync("Manga-Cover-Art-Response.json");

        IHttpService httpService = Substitute.For<IHttpService>();

        httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
            .Returns(Task.FromResult(searchResultJson));

        MangaDexClient mangaDexClient = new(httpService);
        MangaDexResponse? mangaDexResponse = await mangaDexClient.GetCoverArtAsync(Guid.NewGuid(), CancellationToken.None);

        mangaDexResponse.ShouldNotBeNull();
        mangaDexResponse.Response.ShouldBe("collection");
        mangaDexResponse.ShouldBeOfType<MangaDexCollectionResponse>();

        MangaDexCollectionResponse mangaDexEntityResponse = (mangaDexResponse as MangaDexCollectionResponse)!;

        List<CoverArtEntity> coverArtEntities = [.. mangaDexEntityResponse.Data.Where(entity => entity is CoverArtEntity).Cast<CoverArtEntity>()];
        coverArtEntities.Count.ShouldBe(9);

        coverArtEntities[0].Attributes.ShouldNotBeNull();
        coverArtEntities[0].Attributes!.FileName.ShouldBe("2569ffd8-4ba1-4030-8d08-b7a21333a7a6.jpg");

        coverArtEntities[8].Attributes.ShouldNotBeNull();
        coverArtEntities[8].Attributes!.FileName.ShouldBe("6b3073de-bb65-4723-8113-6068bf8c6eb4.jpg");
    }

    private static async Task<string> ReadJsonResourceAsync(string resourceName)
    {
        return await ResourceHelper.ReadJsonResourceAsync($"MangaReader.Tests.Sources.MangaDex.Api.{resourceName}");
    }
}