using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Tiku.Api.Contracts;
using Tiku.Application.Security;
using Tiku.Application.Tenancy;
using Tiku.Domain.Tenancy;

namespace Tiku.Api.Controllers;

[ApiController]
[Tags("租户端-公开配置")]
[AllowAnonymous]
[Produces("application/json")]
[Route("api/public/tenant")]
public sealed class TenantPublicController(
    ITenantContext tenantContext,
    ITenantContextInitializer tenantContextInitializer,
    ITenantDirectory tenantDirectory,
    IPublicTenantConfigurationQuery publicConfiguration) : ControllerBase
{
    [HttpGet("resolve")]
    [EndpointSummary("解析当前租户")]
    [EndpointDescription("根据访问域名、host 参数、x-tenant-code 或 tenantCode 查询启用中的租户及公开品牌配置。")]
    [ProducesResponseType<TenantResolveResponseDto>(StatusCodes.Status200OK)]
    [ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<TenantResolveResponseDto>> Resolve(
        [FromQuery] TenantResolveQueryDto query,
        CancellationToken cancellationToken)
    {
        var tenantCode = NormalizeTenantCode(query.TenantCode ?? Request.Headers["x-tenant-code"].FirstOrDefault());
        var host = NormalizeHost(query.Host ?? Request.Host.Host);

        var directoryEntry = tenantContext.ResolutionSource == TenantResolutionSource.Host
            ? await tenantDirectory.FindByHostAsync(Request.Host.Host, cancellationToken)
            : !string.IsNullOrWhiteSpace(tenantCode)
                ? await tenantDirectory.FindByCodeAsync(tenantCode, cancellationToken)
                : string.IsNullOrWhiteSpace(host)
                    ? null
                    : await tenantDirectory.FindByHostAsync(host, cancellationToken);

        var tenant = directoryEntry is null
            ? null
            : new TenantLookupResult(
                directoryEntry.TenantId,
                directoryEntry.TenantCode,
                directoryEntry.Name,
                directoryEntry.Status,
                directoryEntry.Mode,
                directoryEntry.Host);

        if (tenant is null)
            return NotFound(new ProblemDetails
            {
                Title = "Tenant was not found.",
                Status = StatusCodes.Status404NotFound,
                Detail = "No active tenant matches the supplied host or tenantCode."
            });

        tenantContextInitializer.Initialize(
            tenant.Id,
            tenant.Slug,
            tenant.Host is null ? TenantResolutionSource.TenantCode : TenantResolutionSource.Host);

        return Ok(await BuildResponseAsync(tenant, tenant.Host, cancellationToken));
    }

    [HttpGet("current-public")]
    [EndpointSummary("获取公开租户配置")]
    [EndpointDescription("公开页面使用的租户品牌、功能开关和 public config。和 resolve 返回结构一致。")]
    [ProducesResponseType<TenantResolveResponseDto>(StatusCodes.Status200OK)]
    [ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
    public Task<ActionResult<TenantResolveResponseDto>> CurrentPublic(
        [FromQuery] TenantResolveQueryDto query,
        CancellationToken cancellationToken)
    {
        return Resolve(query, cancellationToken);
    }

    private async Task<TenantResolveResponseDto> BuildResponseAsync(
        TenantLookupResult tenant,
        string? host,
        CancellationToken cancellationToken)
    {
        var configuration = await publicConfiguration.GetAsync(tenant.Id, cancellationToken);

        return new TenantResolveResponseDto(
            new PublicTenantDto(
                tenant.Id,
                tenant.Slug,
                tenant.Name,
                tenant.Status,
                tenant.Mode,
                host),
            new PublicTenantBrandingDto(
                configuration.BrandName,
                configuration.ShortName,
                configuration.Slogan,
                configuration.LogoUrl,
                configuration.FaviconUrl,
                configuration.ServiceWechat,
                configuration.ServiceAccountName,
                configuration.Theme,
                configuration.PublicAssets),
            configuration.FeatureFlags,
            configuration.AdminFeatureFlags,
            configuration.PublicConfig);
    }

    private static string? NormalizeTenantCode(string? value)
    {
        return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
    }

    private static string? NormalizeHost(string? value)
    {
        if (string.IsNullOrWhiteSpace(value)) return null;

        var host = value.Trim().ToLowerInvariant();
        return host.Split(':', 2)[0];
    }

    private sealed record TenantLookupResult(
        Guid Id,
        string Slug,
        string Name,
        TenantStatus Status,
        TenantMode Mode,
        string? Host);
}