using System.Net;
using System.Text.Json;
using Tiku.Domain.Catalog;
using Tiku.Domain.Commerce;
using Tiku.Domain.Common;
using Tiku.Domain.Learning;
using Tiku.Domain.Operations;
using Tiku.Domain.Tenancy;

namespace Tiku.IntegrationTests.Api;

public sealed class CatalogEndpointTests
{
    [Fact]
    public async Task Regions_are_filtered_by_active_tenant()
    {
        var tenantId = Guid.NewGuid();
        var otherTenantId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            Tenant(otherTenantId, "other"),
            new Region
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Name = "浙江",
                SortOrder = 2,
                IsActive = true
            },
            new Region
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Name = "北京",
                SortOrder = 1,
                IsActive = true
            },
            new Region
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Name = "停用地区",
                SortOrder = 0,
                IsActive = false
            },
            new Region
            {
                Id = Guid.NewGuid(),
                TenantId = otherTenantId,
                Name = "其他租户地区",
                IsActive = true
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync("/api/catalog/regions?tenantCode=master");
        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 Subjects_support_common_filters()
    {
        var tenantId = Guid.NewGuid();
        var regionId = Guid.NewGuid();
        var schoolId = Guid.NewGuid();
        var majorId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new Region { Id = regionId, TenantId = tenantId, Name = "浙江" },
            new School { Id = schoolId, TenantId = tenantId, RegionId = regionId, Name = "测试院校" },
            new Major { Id = majorId, TenantId = tenantId, RegionId = regionId, SchoolId = schoolId, Name = "视觉传达" },
            new Subject
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                SchoolId = schoolId,
                MajorId = majorId,
                Name = "专业理论",
                Type = SubjectType.Professional,
                SortOrder = 1,
                IsActive = true
            },
            new Subject
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                SchoolId = schoolId,
                MajorId = majorId,
                Name = "公共英语",
                Type = SubjectType.Cultural,
                SortOrder = 2,
                IsActive = true
            },
            new Subject
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Name = "停用科目",
                Type = SubjectType.Professional,
                IsActive = false
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync(
            $"/api/catalog/subjects?tenantCode=master&regionId={regionId}&schoolId={schoolId}&majorId={majorId}&type=professional&keyword=理论");
        var items = await ReadItemsAsync(response);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var item = Assert.Single(items);
        Assert.Equal("专业理论", item.GetProperty("name").GetString());
    }

    [Fact]
    public async Task Module_nodes_support_root_filter()
    {
        var tenantId = Guid.NewGuid();
        var parentId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new ModuleNode
            {
                Id = parentId,
                TenantId = tenantId,
                Name = "根节点",
                Type = ModuleNodeType.Category,
                IsActive = true
            },
            new ModuleNode
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                ParentId = parentId,
                Name = "子节点",
                Type = ModuleNodeType.Chapter,
                IsActive = true
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync("/api/catalog/module-nodes?tenantCode=master&parentId=root");
        var items = await ReadItemsAsync(response);

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

    [Fact]
    public async Task Catalog_requires_known_tenant_for_anonymous_requests()
    {
        await using var factory = new ApiTestFactory();
        using var client = factory.CreateClient();

        using var response = await client.GetAsync("/api/catalog/regions");
        var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

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

    [Fact]
    public async Task Banners_are_filtered_by_tenant_region_and_active_status()
    {
        var tenantId = Guid.NewGuid();
        var otherTenantId = Guid.NewGuid();
        var regionId = Guid.NewGuid();
        var otherRegionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            Tenant(otherTenantId, "other"),
            new Region { Id = regionId, TenantId = tenantId, Name = "浙江" },
            new Region { Id = otherRegionId, TenantId = tenantId, Name = "江苏" },
            new Banner
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Title = "第二张",
                SortOrder = 2,
                IsActive = true
            },
            new Banner
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Title = "第一张",
                SortOrder = 1,
                IsActive = true
            },
            new Banner
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Title = "停用横幅",
                IsActive = false
            },
            new Banner
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = otherRegionId,
                Title = "其他地区横幅",
                IsActive = true
            },
            new Banner
            {
                Id = Guid.NewGuid(),
                TenantId = otherTenantId,
                Title = "其他租户横幅",
                IsActive = true
            });
        using var client = factory.CreateClient();

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

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(["第一张", "第二张"], items.Select(item => item.GetProperty("title").GetString()!).ToArray());
    }

    [Fact]
    public async Task Faqs_and_announcements_only_return_active_current_tenant_items()
    {
        var tenantId = Guid.NewGuid();
        var otherTenantId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            Tenant(otherTenantId, "other"),
            new Faq
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Question = "如何购买？",
                Answer = "在线购买",
                IsActive = true
            },
            new Faq
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Question = "停用 FAQ",
                IsActive = false
            },
            new Faq
            {
                Id = Guid.NewGuid(),
                TenantId = otherTenantId,
                Question = "其他租户 FAQ",
                IsActive = true
            },
            new Announcement
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Content = "暑期活动",
                IsActive = true
            },
            new Announcement
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Content = "停用公告",
                IsActive = false
            },
            new Announcement
            {
                Id = Guid.NewGuid(),
                TenantId = otherTenantId,
                Content = "其他租户公告",
                IsActive = true
            });
        using var client = factory.CreateClient();

        using var faqResponse = await client.GetAsync("/api/catalog/faqs?tenantCode=master");
        using var announcementResponse = await client.GetAsync("/api/catalog/announcements?tenantCode=master");
        var faqs = await ReadItemsAsync(faqResponse);
        var announcements = await ReadItemsAsync(announcementResponse);

        Assert.Equal(HttpStatusCode.OK, faqResponse.StatusCode);
        Assert.Equal(HttpStatusCode.OK, announcementResponse.StatusCode);
        Assert.Equal("如何购买？", Assert.Single(faqs).GetProperty("question").GetString());
        Assert.Equal("暑期活动", Assert.Single(announcements).GetProperty("content").GetString());
    }

    [Fact]
    public async Task Exam_dates_support_region_school_filters_and_days_left()
    {
        var tenantId = Guid.NewGuid();
        var regionId = Guid.NewGuid();
        var schoolId = Guid.NewGuid();
        var otherRegionId = Guid.NewGuid();
        var otherSchoolId = Guid.NewGuid();
        var futureExamAt = new DateTimeOffset(DateTimeOffset.UtcNow.Date.AddDays(10), TimeSpan.Zero);
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new Region { Id = regionId, TenantId = tenantId, Name = "浙江" },
            new Region { Id = otherRegionId, TenantId = tenantId, Name = "其他地区" },
            new School { Id = schoolId, TenantId = tenantId, RegionId = regionId, Name = "测试院校" },
            new School { Id = otherSchoolId, TenantId = tenantId, RegionId = otherRegionId, Name = "其他院校" },
            new ExamDate
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                SchoolId = schoolId,
                ExamName = "校考",
                ExamAt = futureExamAt,
                IsActive = true
            },
            new ExamDate
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                ExamName = "通用考试",
                ExamAt = futureExamAt.AddDays(1),
                IsActive = true
            },
            new ExamDate
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = otherRegionId,
                SchoolId = otherSchoolId,
                ExamName = "其他地区学校考试",
                ExamAt = futureExamAt.AddDays(2),
                IsActive = true
            },
            new ExamDate
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                SchoolId = schoolId,
                ExamName = "停用考试",
                IsActive = false
            });
        using var client = factory.CreateClient();

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

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(["校考", "通用考试"], items.Select(item => item.GetProperty("examName").GetString()!).ToArray());
        Assert.Equal(10, items[0].GetProperty("daysLeft").GetInt32());
    }

    [Fact]
    public async Task Products_filter_active_region_type_keyword_and_limit()
    {
        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 Product
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Title = "联考资料 B",
                Type = ProductType.Material,
                SortOrder = 2,
                LegacyPriceText = "¥20",
                IsActive = true
            },
            new Product
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Title = "联考资料 A",
                Type = ProductType.Material,
                SortOrder = 1,
                LegacyPriceText = "¥10",
                IsActive = true
            },
            new Product
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Title = "联考课程",
                Type = ProductType.Course,
                IsActive = true
            },
            new Product
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Title = "停用资料",
                Type = ProductType.Material,
                IsActive = false
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync(
            $"/api/catalog/products?tenantCode=master&regionId={regionId}&type=material&keyword=联考&limit=1");
        var items = await ReadItemsAsync(response);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var item = Assert.Single(items);
        Assert.Equal("联考资料 A", item.GetProperty("title").GetString());
        Assert.Equal("¥10", item.GetProperty("priceLabel").GetString());
        Assert.True(item.GetProperty("isActive").GetBoolean());
    }

    [Fact]
    public async Task Svip_plans_filter_active_region_and_include_global_plans()
    {
        var tenantId = Guid.NewGuid();
        var regionId = Guid.NewGuid();
        var otherRegionId = Guid.NewGuid();
        await using var factory = new ApiTestFactory();
        await factory.SeedAsync(
            Tenant(tenantId, "master"),
            new Region { Id = regionId, TenantId = tenantId, Name = "浙江" },
            new Region { Id = otherRegionId, TenantId = tenantId, Name = "其他地区" },
            new SvipPlan
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Name = "地区月卡",
                PriceCents = 3000,
                Days = 30,
                SortOrder = 2,
                IsActive = true
            },
            new SvipPlan
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                Name = "通用周卡",
                PriceCents = 900,
                Days = 7,
                SortOrder = 1,
                IsActive = true
            },
            new SvipPlan
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = otherRegionId,
                Name = "其他地区卡",
                PriceCents = 1000,
                Days = 7,
                IsActive = true
            },
            new SvipPlan
            {
                Id = Guid.NewGuid(),
                TenantId = tenantId,
                RegionId = regionId,
                Name = "停用卡",
                PriceCents = 1,
                Days = 1,
                IsActive = false
            });
        using var client = factory.CreateClient();

        using var response = await client.GetAsync($"/api/catalog/svip-plans?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());
        Assert.Equal(9m, items[0].GetProperty("price").GetDecimal());
    }

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

    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();
    }
}
