namespace TaxBaik.Web.Services;

using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Identity;
using TaxBaik.Application.Services;
using TaxBaik.Domain.Entities;

public class PortalAuthService(
    IHttpContextAccessor httpContextAccessor,
    PortalUserService portalUserService)
{
    private static readonly PasswordHasher<PortalUser> Hasher = new();

    public async Task<bool> SignInAsync(string email, string password, CancellationToken ct = default)
    {
        var httpContext = httpContextAccessor.HttpContext
            ?? throw new InvalidOperationException("HTTP context is unavailable.");

        var user = await portalUserService.GetByEmailAsync(email, ct);
        if (user is null)
            return false;

        if (string.IsNullOrWhiteSpace(user.PasswordHash))
            return false;

        var verify = Hasher.VerifyHashedPassword(user, user.PasswordHash, password);
        if (verify == PasswordVerificationResult.Failed)
            return false;

        var claims = new List<Claim>
        {
            new(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new(ClaimTypes.Name, user.Name),
            new(ClaimTypes.Email, user.Email),
            new("portal_user_id", user.Id.ToString())
        };

        if (user.ClientId.HasValue)
            claims.Add(new("client_id", user.ClientId.Value.ToString()));

        var identity = new ClaimsIdentity(claims, PortalAuthDefaults.Scheme);
        var principal = new ClaimsPrincipal(identity);

        await httpContext.SignInAsync(
            PortalAuthDefaults.Scheme,
            principal,
            new AuthenticationProperties
            {
                IsPersistent = true
            });

        return true;
    }

    public static string HashPassword(string password)
    {
        var tempUser = new PortalUser();
        return Hasher.HashPassword(tempUser, password);
    }

    public async Task SignOutAsync()
    {
        var httpContext = httpContextAccessor.HttpContext
            ?? throw new InvalidOperationException("HTTP context is unavailable.");

        await httpContext.SignOutAsync(PortalAuthDefaults.Scheme);
    }
}
