using Ory.Kratos.Client.Api;
using System.Security.Claims;
using Ory.Kratos.Client.Client;
using System.Text.Encodings.Web;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Authentication;

namespace khmer_eid_backend.Integrations.Ory;

public class KratosHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly FrontendApi _frontendApi;

    public KratosHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        IConfiguration config)
        : base(options, logger, encoder)
    {
        var cfg = new Configuration { BasePath = config["Ory:Kratos:PublicUrl"]! };
        _frontendApi = new FrontendApi(cfg);
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var authHeader = Request.Headers["Authorization"].ToString();
        if (string.IsNullOrWhiteSpace(authHeader) || !authHeader.StartsWith("Bearer "))
            return AuthenticateResult.NoResult();

        var token = authHeader.Substring("Bearer ".Length).Trim();

        try
        {
            var session = await _frontendApi.ToSessionAsync(xSessionToken: token);

            var identity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.NameIdentifier, session.Identity.Id),
                new Claim("phone", session.Identity.Traits.ToString() ?? "")
            }, Scheme.Name);

            var principal = new ClaimsPrincipal(identity);
            return AuthenticateResult.Success(new AuthenticationTicket(principal, Scheme.Name));
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Failed to authenticate Kratos session");
            return AuthenticateResult.Fail("Invalid Kratos session token");
        }
    }
}
