using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Tiku.Application.Tenancy;
using Tiku.Domain.Common;
using Tiku.Domain.Operations;
using Tiku.Domain.Tenancy;

namespace Tiku.IntegrationTests.Api;

public sealed class TenantPublicEndpointTests
{
    [Fact]
    public async Task Runtime_bootstrap_uses_published_config_etag_and_invalidates_after_publish()
    {
        await using var factory = new ApiTestFactory();
        var tenantId = Guid.NewGuid();
        await SeedTenantAsync(factory, tenantId);
        await factory.SeedAsync(new TenantFrontendConfig
        {
            TenantId = tenantId,
            ConfigVersion = 1,
            PublishedBranding = JsonSerializer.SerializeToElement(new { name = "published" }),
            DraftBranding = JsonSerializer.SerializeToElement(new { name = "published" })
        });
        using var client = factory.CreateClient();

        using var firstRequest = new HttpRequestMessage(HttpMethod.Get, "/api/public/runtime/bootstrap");
        firstRequest.Headers.Host = "student.example.test";
        var first = await client.SendAsync(firstRequest);
        var firstBody = await first.Content.ReadFromJsonAsync<JsonElement>();
        var firstEtag = first.Headers.ETag?.Tag;

        using var notModifiedRequest = new HttpRequestMessage(HttpMethod.Get, "/api/public/runtime/bootstrap");
        notModifiedRequest.Headers.Host = "student.example.test";
        notModifiedRequest.Headers.TryAddWithoutValidation("If-None-Match", firstEtag);
        var notModified = await client.SendAsync(notModifiedRequest);

        using (var scope = factory.CreateTenantScope(tenantId, "master"))
        {
            var service = scope.ServiceProvider.GetRequiredService<ITenantFrontendConfigService>();
            await service.SaveDraftAsync(
                tenantId,
                new TenantFrontendConfigDraft(
                    JsonSerializer.SerializeToElement(new { name = "draft" }),
                    JsonDefaults.Object(),
                    JsonDefaults.Object(),
                    JsonDefaults.Array(),
                    JsonDefaults.Array()));
            await service.PublishAsync(tenantId, 1);
        }

        using var publishedRequest = new HttpRequestMessage(HttpMethod.Get, "/api/public/runtime/bootstrap");
        publishedRequest.Headers.Host = "student.example.test";
        var published = await client.SendAsync(publishedRequest);
        var publishedBody = await published.Content.ReadFromJsonAsync<JsonElement>();

        Assert.Equal(HttpStatusCode.OK, first.StatusCode);
        Assert.Equal("published", firstBody.GetProperty("branding").GetProperty("name").GetString());
        Assert.Equal(HttpStatusCode.NotModified, notModified.StatusCode);
        Assert.Equal(HttpStatusCode.OK, published.StatusCode);
        Assert.NotEqual(firstEtag, published.Headers.ETag?.Tag);
        Assert.Equal("draft", publishedBody.GetProperty("branding").GetProperty("name").GetString());
    }

    [Fact]
    public async Task Resolve_returns_public_tenant_configuration_by_tenant_code()
    {
        await using var factory = new ApiTestFactory();
        var tenantId = Guid.NewGuid();
        await SeedTenantAsync(factory, tenantId);
        using var client = factory.CreateClient();

        var response = await client.GetAsync("/api/public/tenant/resolve?tenantCode=master");
        var document = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(tenantId.ToString(), document.RootElement.GetProperty("tenant").GetProperty("id").GetString());
        Assert.Equal("升本刷题通", document.RootElement.GetProperty("branding").GetProperty("brandName").GetString());
        Assert.True(document.RootElement.GetProperty("features").GetProperty("enableVocabulary").GetBoolean());
        Assert.Equal("http://127.0.0.1:5173",
            document.RootElement.GetProperty("publicConfig").GetProperty("appUrl").GetString());
    }

    [Fact]
    public async Task Resolve_returns_public_tenant_configuration_by_host()
    {
        await using var factory = new ApiTestFactory();
        var tenantId = Guid.NewGuid();
        await SeedTenantAsync(factory, tenantId);
        using var client = factory.CreateClient();

        var response = await client.GetAsync("/api/public/tenant/resolve?host=student.example.test");
        var document = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal("student.example.test",
            document.RootElement.GetProperty("tenant").GetProperty("host").GetString());
    }

    [Fact]
    public async Task Resolve_prefers_published_theme_config_over_branding_theme()
    {
        await using var factory = new ApiTestFactory();
        var tenantId = Guid.NewGuid();
        await SeedTenantAsync(factory, tenantId);
        await factory.SeedAsync(new TenantThemeConfig
        {
            TenantId = tenantId,
            Status = TenantThemeConfigStatus.Published,
            ActiveTheme = JsonSerializer.SerializeToElement(new
            {
                color = "red"
            }),
            ActivePublicAssets = JsonSerializer.SerializeToElement(new
            {
                hero = "/hero.png"
            })
        });
        using var client = factory.CreateClient();

        var response = await client.GetAsync("/api/public/tenant/current-public?tenantCode=master");
        var document = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal("red",
            document.RootElement.GetProperty("branding").GetProperty("theme").GetProperty("color").GetString());
        Assert.Equal("/hero.png",
            document.RootElement.GetProperty("branding").GetProperty("publicAssets").GetProperty("hero").GetString());
    }

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

        var response = await client.GetAsync("/api/public/tenant/resolve?tenantCode=missing");

        Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
    }

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

        var response = await client.GetAsync("/api/system/health");
        var body = await response.Content.ReadFromJsonAsync<JsonElement>();

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal("ok", body.GetProperty("status").GetString());
    }

    [Fact]
    public async Task Cors_preflight_allows_configured_development_origin()
    {
        await using var factory = new ApiTestFactory();
        using var client = factory.CreateClient();
        using var request = new HttpRequestMessage(HttpMethod.Options, "/api/system/health");
        request.Headers.Add("Origin", "http://localhost:5173");
        request.Headers.Add("Access-Control-Request-Method", "GET");

        var response = await client.SendAsync(request);

        Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
        Assert.Equal("http://localhost:5173", response.Headers.GetValues("Access-Control-Allow-Origin").Single());
    }

    private static Task SeedTenantAsync(ApiTestFactory factory, Guid tenantId)
    {
        return factory.SeedAsync(
            new Tenant
            {
                Id = tenantId,
                Slug = "master",
                Name = "升本刷题通",
                Status = TenantStatus.Active,
                Mode = TenantMode.Saas
            },
            new TenantDomain
            {
                TenantId = tenantId,
                Host = "student.example.test",
                DomainType = TenantDomainType.Custom,
                Status = TenantDomainStatus.Active,
                IsPrimary = true
            },
            new TenantBranding
            {
                TenantId = tenantId,
                BrandName = "升本刷题通",
                ShortName = "刷题通",
                Slogan = "多租户专升本题库 SaaS",
                LogoUrl = "https://example.test/logo.png",
                FaviconUrl = "https://example.test/favicon.ico",
                ServiceWechat = "service-wechat",
                ServiceAccountName = "服务号",
                Theme = JsonSerializer.SerializeToElement(new
                {
                    color = "blue"
                }),
                PublicAssets = JsonDefaults.Object()
            },
            new TenantSettings
            {
                TenantId = tenantId,
                FeatureFlags = JsonSerializer.SerializeToElement(new
                {
                    enableVocabulary = true
                }),
                AdminFeatureFlags = JsonSerializer.SerializeToElement(new
                {
                    enableTenantManagement = true
                }),
                PublicConfig = JsonSerializer.SerializeToElement(new
                {
                    appUrl = "http://127.0.0.1:5173"
                })
            });
    }
}