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

namespace Tiku.IntegrationTests.Api;

public sealed class QuestionBankEndpointTests
{
    [Fact]
    public async Task Question_banks_return_active_tenant_banks_only()
    {
        var tenantId = Guid.NewGuid();
        var otherTenantId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            PlatformTenant(),
            Tenant(tenantId, "master"),
            Tenant(otherTenantId, "other"),
            new QuestionBank
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Name = "A 题库",
                Status = QuestionBankStatus.Active
            },
            new QuestionBank
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Name = "归档题库",
                Status = QuestionBankStatus.Archived
            },
            new QuestionBank
            {
                Id = Guid.NewGuid(),
                TenantId = otherTenantId,
                Name = "其他租户题库",
                Status = QuestionBankStatus.Active
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync("/api/catalog/question-banks?tenantCode=master");
        var items = await ReadItemsAsync(response);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal("A 题库", Assert.Single(items).GetProperty("name").GetString());
    }

    [Fact]
    public async Task Questions_support_filters_and_current_version_projection()
    {
        var tenantId = Guid.NewGuid();
        var bankId = Guid.NewGuid();
        var subjectId = Guid.NewGuid();
        var categoryId = Guid.NewGuid();
        var collectionId = Guid.NewGuid();
        var includedQuestionId = Guid.NewGuid();
        var excludedQuestionId = Guid.NewGuid();
        var versionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            PlatformTenant(),
            Tenant(tenantId, "master"),
            new Subject { Id = subjectId, TenantId = tenantId, Name = "测试科目" },
            new Category { Id = categoryId, TenantId = tenantId, SubjectId = subjectId, Name = "测试分类" },
            new QuestionBank { Id = bankId, TenantId = tenantId, Name = "题库" },
            new QuestionCollection { Id = collectionId, TenantId = tenantId, Name = "题集", Status = ContentStatus.Active },
            new Question
            {
                Id = excludedQuestionId,
                TenantId = tenantId,
                QuestionBankId = bankId,
                SubjectId = subjectId,
                Type = "choice",
                Status = QuestionStatus.Archived
            });
        await factory.SeedQuestionWithVersionAsync(
            new Question
            {
                Id = includedQuestionId,
                TenantId = tenantId,
                QuestionBankId = bankId,
                SubjectId = subjectId,
                CategoryId = categoryId,
                Type = "choice",
                TypeLabel = "单选题",
                Difficulty = 2,
                Status = QuestionStatus.Published
            },
            new QuestionVersion
            {
                Id = versionId,
                TenantId = tenantId,
                QuestionId = includedQuestionId,
                VersionNo = 2,
                Content = "题干关键词"
            });
        var questionReference = await factory.SeedQuestionReferenceAsync(
            tenantId,
            tenantId,
            includedQuestionId);
        await factory.SeedAsync(new QuestionCollectionItem
        {
            Id = Guid.NewGuid(),
            TenantId = tenantId,
            CollectionId = collectionId,
            QuestionReferenceId = questionReference.Id,
            QuestionOwnerTenantId = tenantId,
            QuestionId = includedQuestionId
        });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync(
            $"/api/catalog/questions?tenantCode=master&questionBankId={bankId}&subjectId={subjectId}&categoryId={categoryId}&collectionId={collectionId}&type=choice&keyword=关键词");
        var items = await ReadItemsAsync(response);

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

    [Fact]
    public async Task Question_detail_returns_not_found_for_archived_question()
    {
        var tenantId = Guid.NewGuid();
        var questionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            PlatformTenant(),
            Tenant(tenantId, "master"),
            new Question
            {
                Id = questionId,
                TenantId = tenantId,
                Type = "choice",
                Status = QuestionStatus.Archived
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync($"/api/catalog/questions/{questionId}?tenantCode=master");
        var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

        Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
        Assert.Equal("question_not_found", body.RootElement.GetProperty("code").GetString());
    }

    [Fact]
    public async Task Question_versions_are_returned_newest_first()
    {
        var tenantId = Guid.NewGuid();
        var questionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            PlatformTenant(),
            Tenant(tenantId, "master"),
            new Question
            {
                Id = questionId,
                TenantId = tenantId,
                Type = "choice",
                Status = QuestionStatus.Published
            },
            new QuestionVersion
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                QuestionId = questionId,
                VersionNo = 1,
                Content = "旧版本"
            },
            new QuestionVersion
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                QuestionId = questionId,
                VersionNo = 2,
                Content = "新版本"
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync($"/api/catalog/questions/{questionId}/versions?tenantCode=master");
        var items = await ReadItemsAsync(response);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(["新版本", "旧版本"], items.Select(item => item.GetProperty("content").GetString()!).ToArray());
    }

    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 Tenant PlatformTenant() => new()
    {
        Id = Guid.NewGuid(),
        Slug = $"platform-{Guid.NewGuid():N}",
        Name = "Platform Question Bank",
        Status = TenantStatus.Active,
        Mode = TenantMode.PlatformOwned,
        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();
    }
}
