using CashLineERP.Contracts.Auth;
using CashLineERP.Contracts.Identity;
using CashLineERP.SharedKernel.Identity;

namespace CashLineERP.Application.Identity;

public sealed class IdentityService : IIdentityService
{
    private readonly IIdentityReadRepository _identityReadRepository;
    private readonly IAccessTokenService _accessTokenService;

    public IdentityService(IIdentityReadRepository identityReadRepository, IAccessTokenService accessTokenService)
    {
        _identityReadRepository = identityReadRepository;
        _accessTokenService = accessTokenService;
    }

    public LoginResponse Login(LoginRequest request)
    {
        var user = _identityReadRepository.FindByLoginName(request.Username);
        if (user is null || !user.IsActive || user.IsLocked)
        {
            throw new InvalidOperationException("User is not available for sign-in.");
        }

        if (!PasswordSecurity.VerifyPassword(request.Password, user.PasswordHash))
        {
            throw new InvalidOperationException("Invalid username or password.");
        }

        var inferredPortalCode = string.Equals(
            user.UserTypeCode,
            UserTypeCode.External,
            StringComparison.OrdinalIgnoreCase)
            ? PortalCode.External
            : PortalCode.Internal;
        var requiresMfa = string.Equals(inferredPortalCode, PortalCode.Internal, StringComparison.OrdinalIgnoreCase)
            && !IsFormalUatIdentity(user);

        return new LoginResponse(
            AccessToken: _accessTokenService.IssueToken(user),
            RefreshToken: string.Empty,
            ExpiresInSeconds: 3600,
            MfaRequired: requiresMfa);
    }

    public AuthenticatedUserProfileResponse GetCurrentUserProfile(long userId)
    {
        var user = _identityReadRepository.FindByUserId(userId)
            ?? throw new InvalidOperationException("Authenticated user profile could not be resolved.");

        return new AuthenticatedUserProfileResponse(
            Username: user.LoginName,
            DisplayName: user.DisplayName,
            UserType: user.UserTypeCode,
            Email: user.Email,
            BranchId: user.BranchId,
            PartyId: user.PartyId,
            Workspace: ResolveWorkspace(user),
            RoleCodes: user.RoleCodes,
            FunctionCodes: user.FunctionCodes);
    }

    public IReadOnlyCollection<RoleSummaryResponse> GetRoles()
    {
        return _identityReadRepository
            .GetRoles()
            .Select(role => new RoleSummaryResponse(
                role.RoleCode,
                role.RoleName,
                role.PortalCode,
                role.IsChecker))
            .ToArray();
    }

    private static bool IsFormalUatIdentity(ApplicationUserIdentityView user)
    {
        return user.LoginName.EndsWith("@uat.cashline.test", StringComparison.OrdinalIgnoreCase)
            || (user.Email?.EndsWith("@uat.cashline.test", StringComparison.OrdinalIgnoreCase) ?? false);
    }

    private static string ResolveWorkspace(ApplicationUserIdentityView user)
    {
        if (user.RoleCodes.Contains("SUPER_ADMIN", StringComparer.OrdinalIgnoreCase))
        {
            return "administrator";
        }

        if (user.RoleCodes.Contains("SYSTEM_OWNER", StringComparer.OrdinalIgnoreCase))
        {
            return "system-owner";
        }

        if (user.RoleCodes.Contains("ACCOUNTING_OFFICE_SUPERVISOR", StringComparer.OrdinalIgnoreCase)
            || user.RoleCodes.Contains("ACCOUNTING_OFFICE_USER", StringComparer.OrdinalIgnoreCase))
        {
            return "accounting-office";
        }

        if (user.RoleCodes.Contains("EXTERNAL_SUPPLIER_USER", StringComparer.OrdinalIgnoreCase)
            || user.RoleCodes.Contains("SUPPLIER_ADMIN", StringComparer.OrdinalIgnoreCase))
        {
            return "supplier";
        }

        if (user.RoleCodes.Contains("EXTERNAL_CUSTOMER_USER", StringComparer.OrdinalIgnoreCase)
            || user.RoleCodes.Contains("CUSTOMER_ADMIN", StringComparer.OrdinalIgnoreCase))
        {
            return "customer";
        }

        if (user.RoleCodes.Contains("IF_OPERATIONS_MAKER", StringComparer.OrdinalIgnoreCase))
        {
            return "islamic";
        }

        if (user.RoleCodes.Any(roleCode => roleCode.StartsWith("FINANCE_", StringComparison.OrdinalIgnoreCase)))
        {
            return user.RoleCodes.Contains("FINANCE_CHECKER", StringComparer.OrdinalIgnoreCase)
                ? "finance-checker"
                : "finance";
        }

        if (user.RoleCodes.Contains("ERP_PROCUREMENT_MAKER", StringComparer.OrdinalIgnoreCase))
        {
            return "procurement";
        }

        if (user.RoleCodes.Contains("ERP_INVENTORY_CONTROLLER", StringComparer.OrdinalIgnoreCase))
        {
            return "inventory";
        }

        if (user.RoleCodes.Contains("ERP_SALES_OPERATOR", StringComparer.OrdinalIgnoreCase))
        {
            return "sales";
        }

        if (user.RoleCodes.Contains("ERP_OPS_MAKER", StringComparer.OrdinalIgnoreCase))
        {
            return "operations";
        }

        var loginOrEmail = $"{user.LoginName}|{user.Email}".ToLowerInvariant();
        if (loginOrEmail.Contains("supplier"))
        {
            return "supplier";
        }

        if (loginOrEmail.Contains("customer"))
        {
            return "customer";
        }

        if (loginOrEmail.Contains("accounting") || loginOrEmail.Contains("accountant"))
        {
            return "accounting-office";
        }

        if (loginOrEmail.Contains("islamic"))
        {
            return "islamic";
        }

        if (loginOrEmail.Contains("procurement") || loginOrEmail.Contains("proc"))
        {
            return "procurement";
        }

        if (loginOrEmail.Contains("inventory") || loginOrEmail.Contains("inv_ctrl"))
        {
            return "inventory";
        }

        if (loginOrEmail.Contains("sales"))
        {
            return "sales";
        }

        if (loginOrEmail.Contains("operations") || loginOrEmail.Contains("ops"))
        {
            return "operations";
        }

        return "general";
    }
}
