using System.Net;
using System.Text.Json;
using Tiku.Domain.Catalog;
using Tiku.Domain.Common;
using Tiku.Domain.Content;
using Tiku.Domain.QuestionBanks;
using Tiku.Domain.Tenancy;

namespace Tiku.IntegrationTests.Api;

public sealed class ContentNavigationEndpointTests
{
    [Fact]
    public async Task Content_entries_hide_hidden_items_by_default()
    {
        var tenantId = Guid.NewGuid();
        var regionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new Region { Id = regionId, TenantId = tenantId, Name = "测试地区" },
            new ContentEntry
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                EntryKey = "practice",
                Name = "公开练习",
                EntryType = ContentEntryType.QuestionPractice,
                Visibility = ContentVisibility.Public,
                SortOrder = 2
            },
            new ContentEntry
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                EntryKey = "global",
                Name = "全局入口",
                EntryType = ContentEntryType.QuestionPractice,
                Visibility = ContentVisibility.Public,
                SortOrder = 1
            },
            new ContentEntry
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                EntryKey = "hidden",
                Name = "隐藏入口",
                EntryType = ContentEntryType.QuestionPractice,
                Visibility = ContentVisibility.Hidden
            });
        using var client = factory.CreateClient();

        using var response =
            await client.GetAsync($"/api/public/catalog/content-entries?tenantCode=master&regionId={regionId}");
        var items = await ReadItemsAsync(response);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(["全局入口", "公开练习"], items.Select(item => item.GetProperty("name").GetString()!).ToArray());
    }

    [Fact]
    public async Task Content_nodes_support_required_entry_and_root_filter()
    {
        var tenantId = Guid.NewGuid();
        var entryId = Guid.NewGuid();
        var rootNodeId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new ContentEntry
            {
                Id = entryId,
                TenantId = tenantId,
                EntryKey = "practice",
                Name = "练习入口"
            },
            new ContentNode
            {
                Id = rootNodeId,
                TenantId = tenantId,
                EntryId = entryId,
                Name = "根内容节点",
                NodeKey = "root",
                SortOrder = 1,
                IsLeaf = false
            },
            new ContentNode
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                EntryId = entryId,
                ParentId = rootNodeId,
                Name = "子内容节点",
                NodeKey = "child",
                SortOrder = 2,
                IsLeaf = true
            });
        using var client = factory.CreateClient();

        using var missingEntryResponse = await client.GetAsync("/api/public/catalog/content-nodes?tenantCode=master");
        using var response =
            await client.GetAsync(
                $"/api/public/catalog/content-nodes?tenantCode=master&entryId={entryId}&parentId=root");
        var items = await ReadItemsAsync(response);

        Assert.Equal(HttpStatusCode.BadRequest, missingEntryResponse.StatusCode);
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var item = Assert.Single(items);
        Assert.Equal("根内容节点", item.GetProperty("name").GetString());
    }

    [Fact]
    public async Task Collections_and_blueprints_return_active_items_only()
    {
        var tenantId = Guid.NewGuid();
        var entryId = Guid.NewGuid();
        var nodeId = Guid.NewGuid();
        var collectionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new ContentEntry { Id = entryId, TenantId = tenantId, EntryKey = "practice", Name = "练习入口" },
            new ContentNode { Id = nodeId, TenantId = tenantId, EntryId = entryId, Name = "章节" },
            new QuestionCollection
            {
                Id = collectionId,
                TenantId = tenantId,
                EntryId = entryId,
                NodeId = nodeId,
                Name = "章节题集",
                CollectionType = QuestionCollectionType.Chapter,
                Status = ContentStatus.Active,
                SortOrder = 1
            },
            new QuestionCollection
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                EntryId = entryId,
                NodeId = nodeId,
                Name = "草稿题集",
                Status = ContentStatus.Draft
            },
            new PracticeBlueprint
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                EntryId = entryId,
                NodeId = nodeId,
                CollectionId = collectionId,
                Name = "章节练习",
                Mode = PracticeMode.Sequential,
                Status = ContentStatus.Active
            },
            new PracticeBlueprint
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                EntryId = entryId,
                NodeId = nodeId,
                CollectionId = collectionId,
                Name = "归档练习",
                Mode = PracticeMode.Sequential,
                Status = ContentStatus.Archived
            });
        using var client = factory.CreateClient();

        using var collectionsResponse = await client.GetAsync(
            $"/api/public/catalog/question-collections?tenantCode=master&entryId={entryId}&nodeId={nodeId}&collectionType=chapter");
        using var blueprintsResponse = await client.GetAsync(
            $"/api/public/catalog/practice-blueprints?tenantCode=master&entryId={entryId}&nodeId={nodeId}&collectionId={collectionId}&mode=sequential");
        var collections = await ReadItemsAsync(collectionsResponse);
        var blueprints = await ReadItemsAsync(blueprintsResponse);

        Assert.Equal(HttpStatusCode.OK, collectionsResponse.StatusCode);
        Assert.Equal(HttpStatusCode.OK, blueprintsResponse.StatusCode);
        Assert.Equal("章节题集", Assert.Single(collections).GetProperty("name").GetString());
        Assert.Equal("章节练习", Assert.Single(blueprints).GetProperty("name").GetString());
    }

    [Fact]
    public async Task Collection_questions_return_published_questions_only()
    {
        var tenantId = Guid.NewGuid();
        var collectionId = Guid.NewGuid();
        var publishedQuestionId = Guid.NewGuid();
        var archivedQuestionId = Guid.NewGuid();
        var versionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new QuestionCollection
            {
                Id = collectionId,
                TenantId = tenantId,
                Name = "真题套卷",
                Status = ContentStatus.Active
            },
            new Question
            {
                Id = archivedQuestionId,
                TenantId = tenantId,
                PrimaryCollectionId = collectionId,
                Type = "choice",
                Status = QuestionStatus.Archived
            });
        var archivedReference = await factory.SeedQuestionReferenceAsync(
            tenantId,
            tenantId,
            archivedQuestionId);
        await factory.SeedAsync(new QuestionCollectionItem
        {
            Id = Guid.NewGuid(),
            TenantId = tenantId,
            CollectionId = collectionId,
            QuestionReferenceId = archivedReference.Id,
            QuestionOwnerTenantId = tenantId,
            QuestionId = archivedQuestionId,
            SortOrder = 2
        });
        await factory.SeedQuestionWithVersionAsync(
            new Question
            {
                Id = publishedQuestionId,
                TenantId = tenantId,
                PrimaryCollectionId = collectionId,
                Type = "choice",
                TypeLabel = "单选题",
                Status = QuestionStatus.Published
            },
            new QuestionVersion
            {
                Id = versionId,
                TenantId = tenantId,
                QuestionId = publishedQuestionId,
                Content = "题干"
            });
        var publishedReference = await factory.SeedQuestionReferenceAsync(
            tenantId,
            tenantId,
            publishedQuestionId);
        await factory.SeedAsync(new QuestionCollectionItem
        {
            Id = Guid.NewGuid(),
            TenantId = tenantId,
            CollectionId = collectionId,
            QuestionReferenceId = publishedReference.Id,
            QuestionOwnerTenantId = tenantId,
            QuestionId = publishedQuestionId,
            SortOrder = 1,
            Score = 2
        });
        using var client = factory.CreateClient();

        using var response =
            await client.GetAsync(
                $"/api/public/catalog/question-collections/questions?tenantCode=master&collectionId={collectionId}");
        var items = await ReadItemsAsync(response);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var item = Assert.Single(items);
        Assert.Equal(publishedQuestionId, item.GetProperty("id").GetGuid());
        Assert.Equal("题干", item.GetProperty("content").GetString());
    }

    private static Tenant Tenant(Guid id, string slug)
    {
        return new Tenant
        {
            Id = id,
            Slug = slug,
            Name = slug,
            Status = TenantStatus.Active,
            Metadata = JsonDefaults.Object()
        };
    }

    private static async Task<JsonElement[]> ReadItemsAsync(HttpResponseMessage response)
    {
        var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
        return body.RootElement
            .GetProperty("items")
            .EnumerateArray()
            .Select(item => item.Clone())
            .ToArray();
    }
}