using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using Tiku.Api.Contracts;
using Tiku.Application.Auth;
using Tiku.Application.Growth;
using Tiku.Domain.Commerce;
using Tiku.Domain.Growth;
using Tiku.Domain.Identity;
using Tiku.Domain.Tenancy;
using Tiku.Infrastructure.Auth;

namespace Tiku.IntegrationTests.Api;

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

        var response = await client.GetAsync("/api/commission/settings");

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

    [Fact]
    public async Task Admin_can_generate_export_and_proof_commission_settlement()
    {
        await using var factory = new ApiTestFactory();
        var seed = await SeedCommissionAsync(factory);
        using var client = factory.CreateClient();
        await LoginAsync(client, seed.Admin);

        var settings = await client.PutAsJsonAsync(
            "/api/commission/settings",
            new UpdateCommissionSettingsDto { DefaultRate = 0.2m, MinSettlementCents = 1, SettlementCycle = "monthly" });
        var sources = await client.GetAsync($"/api/commission/orders?referrerUserId={seed.Referrer.UserId}&startDate=2026-07-01&endDate=2026-07-31");
        var summary = await client.GetAsync($"/api/commission/summary?referrerUserId={seed.Referrer.UserId}&startDate=2026-07-01&endDate=2026-07-31");
        var generate = await client.PostAsJsonAsync(
            "/api/commission/settlements/generate",
            new GenerateCommissionSettlementDto
            {
                ReferrerUserId = seed.Referrer.UserId,
                StartDate = "2026-07-01",
                EndDate = "2026-07-31",
                Status = "pending_review"
            });
        var settlement = await generate.Content.ReadFromJsonAsync<CommissionSettlementItemDto>();
        var duplicate = await client.PostAsJsonAsync(
            "/api/commission/settlements/generate",
            new GenerateCommissionSettlementDto
            {
                ReferrerUserId = seed.Referrer.UserId,
                StartDate = "2026-07-01",
                EndDate = "2026-07-31"
            });
        var status = await client.PostAsJsonAsync(
            "/api/commission/settlements/status",
            new UpdateCommissionSettlementStatusDto
            {
                SettlementId = settlement!.Id,
                Status = "paid",
                PaymentMethod = "bank",
                PaymentAccount = "****1234"
            });
        var proof = await client.PostAsJsonAsync(
            "/api/commission/settlements/proofs",
            new CreateCommissionProofDto
            {
                SettlementId = settlement.Id,
                ProofType = "payment",
                ExternalUrl = "https://example.test/proof.png"
            });
        var proofItem = await proof.Content.ReadFromJsonAsync<CommissionProofItem>();
        var proofStatus = await client.PostAsJsonAsync(
            "/api/commission/settlements/proofs/status",
            new UpdateCommissionProofStatusDto { ProofId = proofItem!.Id, Status = "approved" });
        var export = await client.GetAsync($"/api/commission/settlements/export?settlementId={settlement.Id}&format=csv");
        var exportItem = await export.Content.ReadFromJsonAsync<CommissionExportItem>();

        Assert.Equal(HttpStatusCode.OK, settings.StatusCode);
        Assert.Equal(HttpStatusCode.OK, sources.StatusCode);
        Assert.Equal(HttpStatusCode.OK, summary.StatusCode);
        Assert.Equal(HttpStatusCode.OK, generate.StatusCode);
        Assert.Equal(2, settlement.SourceCount);
        Assert.Equal(3000, settlement.CommissionAmountCents);
        Assert.Equal(HttpStatusCode.Conflict, duplicate.StatusCode);
        Assert.Equal(HttpStatusCode.OK, status.StatusCode);
        Assert.Equal(HttpStatusCode.OK, proof.StatusCode);
        Assert.Equal(HttpStatusCode.OK, proofStatus.StatusCode);
        Assert.Equal(HttpStatusCode.OK, export.StatusCode);
        Assert.Equal("csv", exportItem!.Format);
        Assert.False(string.IsNullOrWhiteSpace(exportItem.Sha256));
    }

    private static async Task<CommissionSeed> SeedCommissionAsync(ApiTestFactory factory)
    {
        var tenantId = Guid.NewGuid();
        var admin = new LoginSeed(tenantId, Guid.NewGuid(), "13800003001");
        var referrer = new LoginSeed(tenantId, Guid.NewGuid(), "13800003002");
        var student = new LoginSeed(tenantId, Guid.NewGuid(), "13800003003");
        var paidAt = new DateTimeOffset(2026, 7, 10, 12, 0, 0, TimeSpan.Zero);
        var batchId = Guid.NewGuid();
        await factory.SeedAsync(
            new Tenant { Id = tenantId, Slug = tenantId.ToString("N"), Name = "Commission Tenant" },
            User(admin, "tenant_admin"),
            User(referrer, "sales"),
            User(student, "student"),
            Membership(admin, TenantRole.TenantAdmin),
            Membership(referrer, TenantRole.Sales),
            Membership(student, TenantRole.Student),
            new ReferralLead
            {
                TenantId = tenantId,
                StudentUserId = student.UserId,
                ReferrerUserId = referrer.UserId,
                RefCode = "COMM2026",
                Source = "manual"
            },
            new Order
            {
                TenantId = tenantId,
                UserId = student.UserId,
                OrderNo = "C202607100001",
                Status = OrderStatus.Paid,
                AmountCents = 10000,
                ProductType = "svip",
                ProductName = "SVIP",
                PaidAt = paidAt
            },
            new CodeBatch
            {
                Id = batchId,
                TenantId = tenantId,
                Name = "代理码",
                TotalCount = 1,
                DefaultUnitPriceCents = 5000,
                CommissionRate = 0.2m
            },
            new ActivationCode
            {
                TenantId = tenantId,
                BatchId = batchId,
                AgentUserId = referrer.UserId,
                UsedBy = student.UserId,
                Code = "CODE2026",
                IsUsed = true,
                UnitPriceCents = 5000,
                UsedAt = paidAt
            });
        return new CommissionSeed(tenantId, admin, referrer, student);
    }

    private static User User(LoginSeed seed, string role) =>
        new User { Id = seed.UserId, Phone = seed.Phone, Name = role, PrimaryRole = role }.WithTestPassword();
    private static TenantMembership Membership(LoginSeed seed, TenantRole role) => new() { TenantId = seed.TenantId, UserId = seed.UserId, Role = role, Status = MembershipStatus.Active };

    private static async Task LoginAsync(HttpClient client, LoginSeed seed)
    {
        client.UseAccessToken(await client.LoginAsTenantAsync(seed.TenantId, seed.Phone));
    }

    private sealed record LoginSeed(Guid TenantId, Guid UserId, string Phone);
    private sealed record CommissionSeed(Guid TenantId, LoginSeed Admin, LoginSeed Referrer, LoginSeed Student);
}
