using Microsoft.Extensions.Options;
using Tiku.Api.Options;
using Tiku.Application.Auth;
using Tiku.Application.Content;
using Tiku.Application.Security;
using Tiku.Application.Tenancy;
using Tiku.Domain.Tenancy;

namespace Tiku.Api.Controllers;

public sealed class AuthRequestContextResolver(
    IAuthSessionStore sessionStore,
    ITenantContext tenantContext,
    ITenantContextInitializer tenantContextInitializer,
    ITenantDirectory tenantDirectory,
    IOptions<TenantResolutionOptions> tenantResolutionOptions)
{
    internal void ResolveRefreshTokenTenant(string refreshToken, HttpRequest request)
    {
        if (!sessionStore.TryParseRefreshToken(refreshToken, out var locator)) return;

        if (locator.Realm == AuthRealm.Platform)
        {
            EnsurePlatformHost(request);
            if (tenantContext.IsResolved)
                throw new TenantContextConflictException(tenantContext.TenantId!.Value, Guid.Empty);
            return;
        }

        if (!tenantContext.IsResolved)
            throw new RequiredFieldException(
                "tenant refresh/logout requires a tenant host or x-tenant-code matching the refresh token.");

        tenantContextInitializer.Initialize(locator.TenantId!.Value, null, TenantResolutionSource.RefreshToken);
    }

    internal void ResolveAuthChallengeTenant(string challengeToken, HttpRequest request)
    {
        var parts = challengeToken.Split('.', 4);
        if (parts.Length != 4 || parts[0] != "c1") return;

        if (parts[1] == "p" && parts[2] == "-")
        {
            EnsurePlatformHost(request);
            if (tenantContext.IsResolved)
                throw new TenantContextConflictException(tenantContext.TenantId!.Value, Guid.Empty);
            return;
        }

        if (parts[1] != "t" || !Guid.TryParseExact(parts[2], "N", out var tenantId) || !tenantContext.IsResolved)
            throw new RequiredFieldException(
                "tenant authentication challenge requires a tenant host or x-tenant-code.");

        tenantContextInitializer.Initialize(tenantId, null, TenantResolutionSource.RefreshToken);
    }

    internal async Task<Guid?> ResolveRealmTenantIdAsync(
        AuthRealm realm,
        string? tenantCode,
        HttpRequest request,
        CancellationToken cancellationToken)
    {
        if (realm == AuthRealm.Platform)
        {
            EnsurePlatformHost(request);
            if (tenantContext.IsResolved || !string.IsNullOrWhiteSpace(tenantCode))
                throw new RequiredFieldException(
                    "platform realm does not accept tenantCode and must use a platform host.");

            return null;
        }

        if (tenantContext.TenantId.HasValue)
        {
            if (!string.IsNullOrWhiteSpace(tenantCode) &&
                !string.Equals(tenantContext.TenantCode, tenantCode.Trim(), StringComparison.OrdinalIgnoreCase))
            {
                var supplied = await tenantDirectory.FindByCodeAsync(tenantCode.Trim(), cancellationToken);
                if (supplied?.TenantId != tenantContext.TenantId.Value)
                    throw new TenantContextConflictException(
                        tenantContext.TenantId.Value,
                        supplied?.TenantId ?? Guid.Empty);
            }

            return tenantContext.TenantId.Value;
        }

        if (string.IsNullOrWhiteSpace(tenantCode))
            throw new RequiredFieldException("tenantCode is required when the request host does not resolve a tenant.");

        var tenant = await tenantDirectory.FindByCodeAsync(tenantCode.Trim(), cancellationToken)
                     ?? throw new TenantNotFoundException();
        tenantContextInitializer.Initialize(
            tenant.TenantId,
            tenant.TenantCode,
            TenantResolutionSource.TenantCode);
        return tenant.TenantId;
    }

    internal void EnsureRouteRealm(AuthRealm realm, HttpRequest request)
    {
        var path = request.Path.Value ?? string.Empty;
        var expectedRealm = path.StartsWith("/api/platform/auth/", StringComparison.OrdinalIgnoreCase)
            ? AuthRealm.Platform
            : AuthRealm.Tenant;
        if (realm != expectedRealm)
            throw new RequiredFieldException(
                $"{realm.ToString().ToLowerInvariant()} realm must use the {expectedRealm.ToString().ToLowerInvariant()} authentication route.");
    }

    private void EnsurePlatformHost(HttpRequest request)
    {
        var requestHost = request.Host.Host.Trim().TrimEnd('.');
        if (!tenantResolutionOptions.Value.PlatformHosts.Any(host =>
                string.Equals(
                    host.Trim().TrimEnd('.'),
                    requestHost,
                    StringComparison.OrdinalIgnoreCase)))
            throw new RequiredFieldException("platform realm is only available on a configured platform host.");
    }
}
