using Ablera.Serdica.DBModels.Serdica;
using Ablera.Serdica.Authority.Plugins.Base.Contracts;
using Ablera.Serdica.Authority.Plugins.Base.Models;
using Microsoft.AspNetCore.Identity;
using System.Security.Claims;
using Ablera.Serdica.Common.Tools.Extensions;
using Microsoft.EntityFrameworkCore;
using Ablera.Serdica.Authority.Plugin.Standard.Models;

namespace Ablera.Serdica.Authority.Plugin.Standard;

public class IdentityManagementFacade(
        SerdicaDbContext context,
        IUserManagementFacade<UserAccountIdentityUser> userAccountIdentityFacade)
        : IUserManagementFacade<IdentityUser<string>>
{

    #region IAuthService

    public async Task<AuthenticationResult> AuthenticateAsync(IdentityUser<string> identityUser,
                                                              string password,
                                                              bool lockoutOnFailure = false,
                                                              CancellationToken ct = default)
    {

        var user = await context.UserAccounts
                             .FirstOrDefaultAsync(u => u.UserGuid == identityUser.Id, ct);

        if (user == null)
            return AuthenticationResult.Fail(AuthenticationCode.AccountIsNotFound.ToScreamingSnakeCase());

        if (string.IsNullOrWhiteSpace(password))
            return AuthenticationResult.Fail(AuthenticationCode.EmptyCredentials.ToScreamingSnakeCase());

        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = user };
        return await userAccountIdentityFacade.AuthenticateAsync(userAccountIdentityUser, password, lockoutOnFailure, ct);
    }

    #endregion

    #region IUserStore – best‑effort mapping

    public async Task<IdentityUser<string>?> FindByEmailAsync(string email, CancellationToken ct = default)
        => (await userAccountIdentityFacade.FindByEmailAsync(email, ct))?.Identity;

    public async Task<IdentityUser<string>?> FindByNameAsync(string username, CancellationToken ct = default)
        => (await userAccountIdentityFacade.FindByNameAsync(username, ct))?.Identity;

    public async Task<IdentityUser<string>?> FindByIdAsync(string id, CancellationToken ct = default)
        => (await userAccountIdentityFacade.FindByIdAsync(id, ct))?.Identity;

    public Task<OperationResult> CreateAsync(IdentityUser<string> identityUser, string password, CancellationToken ct = default)
    {
        if (identityUser == null) return Task.FromResult(OperationResult.Fail("NULL_USER"));

        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };

        return userAccountIdentityFacade.CreateAsync(userAccountIdentityUser, password, ct);
    }

    public Task<OperationResult> UpdateAsync(IdentityUser<string> identityUser, CancellationToken ct = default)
    {
        if (identityUser == null) return Task.FromResult(OperationResult.Fail("NULL_USER"));

        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };

        return userAccountIdentityFacade.UpdateAsync(userAccountIdentityUser, ct);
    }

    #endregion

    #region Claim helpers

    public Task<IReadOnlyCollection<Claim>> GetBaseClaimsAsync(IdentityUser<string> identityUser, CancellationToken ct = default)
    {
        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };
        return userAccountIdentityFacade.GetBaseClaimsAsync(userAccountIdentityUser, ct);
    }


    public Task<IReadOnlyCollection<Claim>?> GetRolesClaimsAsync(IdentityUser<string> identityUser, CancellationToken ct = default)
    {
        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };
        return userAccountIdentityFacade.GetRolesClaimsAsync(userAccountIdentityUser, ct);
    }

    #endregion

    #region Password & lock operations – delegated

    public Task<OperationResult> ChangePasswordAsync(IdentityUser<string> identityUser, string currentPassword, string newPassword, CancellationToken ct = default)
    {
        if (identityUser == null) return Task.FromResult(OperationResult.Fail("NULL_USER"));

        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };
        return userAccountIdentityFacade.ChangePasswordAsync(userAccountIdentityUser, currentPassword, newPassword, ct);
    }

    public Task<OperationResult> ResetPasswordAsync(IdentityUser<string> identityUser, string token, string newPassword, CancellationToken ct = default)
    {
        if (identityUser == null) return Task.FromResult(OperationResult.Fail("NULL_USER"));

        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };
        return userAccountIdentityFacade.ResetPasswordAsync(userAccountIdentityUser, token, newPassword, ct);
    }

    public Task<OperationResult> LockAsync(IdentityUser<string> identityUser, CancellationToken ct = default)
    {
        if (identityUser == null) return Task.FromResult(OperationResult.Fail("NULL_USER"));

        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };
        return userAccountIdentityFacade.LockAsync(userAccountIdentityUser, ct);
    }

    public Task<OperationResult> UnlockAsync(IdentityUser<string> identityUser, CancellationToken ct = default)
    {
        if (identityUser == null) return Task.FromResult(OperationResult.Fail("NULL_USER"));

        var userAccountIdentityUser = new UserAccountIdentityUser { Identity = identityUser, UserAccount = null! };
        return userAccountIdentityFacade.UnlockAsync(userAccountIdentityUser, ct);
    }

    #endregion
}
