// EN: Implementation of social login service
// VI: Implementation của social login service
using IamService.Domain.AggregatesModel.UserAggregate;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;

namespace IamService.Infrastructure.SocialLogin;

/// <summary>
/// EN: Service for handling social login operations.
/// VI: Service xử lý các thao tác social login.
/// </summary>
public class SocialLoginService : ISocialLoginService
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly ILogger<SocialLoginService> _logger;

    public SocialLoginService(
        UserManager<ApplicationUser> userManager,
        ILogger<SocialLoginService> logger)
    {
        _userManager = userManager;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<ExternalAuthResult> ProcessExternalLoginAsync(
        string provider,
        string providerUserId,
        string email,
        string? name,
        string? pictureUrl)
    {
        _logger.LogInformation(
            "EN: Processing external login for provider {Provider}, email {Email} / VI: Xử lý đăng nhập bên ngoài cho provider {Provider}, email {Email}",
            provider, email);

        try
        {
            // EN: Try to find user by external login
            // VI: Thử tìm user bằng external login
            var user = await _userManager.FindByLoginAsync(provider, providerUserId);

            if (user != null)
            {
                _logger.LogInformation(
                    "EN: Found existing user by external login / VI: Tìm thấy user hiện có bằng external login");

                return new ExternalAuthResult
                {
                    Success = true,
                    Provider = provider,
                    ProviderUserId = providerUserId,
                    Email = email,
                    Name = name,
                    PictureUrl = pictureUrl,
                    User = user,
                    IsNewUser = false
                };
            }

            // EN: Try to find user by email
            // VI: Thử tìm user bằng email
            user = await _userManager.FindByEmailAsync(email);

            if (user != null)
            {
                // EN: Link external login to existing user
                // VI: Liên kết external login với user hiện có
                var loginInfo = new UserLoginInfo(provider, providerUserId, provider);
                var linkResult = await _userManager.AddLoginAsync(user, loginInfo);

                if (!linkResult.Succeeded)
                {
                    var errors = string.Join(", ", linkResult.Errors.Select(e => e.Description));
                    _logger.LogWarning(
                        "EN: Failed to link external login: {Errors} / VI: Không thể liên kết external login: {Errors}",
                        errors);

                    return new ExternalAuthResult
                    {
                        Success = false,
                        ErrorMessage = $"Failed to link external account: {errors}"
                    };
                }

                _logger.LogInformation(
                    "EN: Linked external login to existing user / VI: Đã liên kết external login với user hiện có");

                return new ExternalAuthResult
                {
                    Success = true,
                    Provider = provider,
                    ProviderUserId = providerUserId,
                    Email = email,
                    Name = name,
                    PictureUrl = pictureUrl,
                    User = user,
                    IsNewUser = false
                };
            }

            // EN: Create new user
            // VI: Tạo user mới
            var firstName = name?.Split(' ').FirstOrDefault() ?? "User";
            var lastName = name?.Split(' ').Skip(1).FirstOrDefault() ?? email.Split('@').First();
            
            user = new ApplicationUser(email, firstName, lastName)
            {
                EmailConfirmed = true // EN: Email verified by provider / VI: Email đã được provider xác minh
            };

            var createResult = await _userManager.CreateAsync(user);
            if (!createResult.Succeeded)
            {
                var errors = string.Join(", ", createResult.Errors.Select(e => e.Description));
                _logger.LogWarning(
                    "EN: Failed to create user: {Errors} / VI: Không thể tạo user: {Errors}",
                    errors);

                return new ExternalAuthResult
                {
                    Success = false,
                    ErrorMessage = $"Failed to create user: {errors}"
                };
            }

            // EN: Add external login to new user
            // VI: Thêm external login cho user mới
            var addLoginInfo = new UserLoginInfo(provider, providerUserId, provider);
            var addLoginResult = await _userManager.AddLoginAsync(user, addLoginInfo);

            if (!addLoginResult.Succeeded)
            {
                _logger.LogWarning(
                    "EN: Failed to add external login for new user / VI: Không thể thêm external login cho user mới");
            }

            // EN: Add default role
            // VI: Thêm role mặc định
            await _userManager.AddToRoleAsync(user, "User");

            _logger.LogInformation(
                "EN: Created new user from external login / VI: Đã tạo user mới từ external login");

            return new ExternalAuthResult
            {
                Success = true,
                Provider = provider,
                ProviderUserId = providerUserId,
                Email = email,
                Name = name,
                PictureUrl = pictureUrl,
                User = user,
                IsNewUser = true
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex,
                "EN: Error processing external login / VI: Lỗi xử lý external login");

            return new ExternalAuthResult
            {
                Success = false,
                ErrorMessage = "An error occurred during external authentication"
            };
        }
    }

    /// <inheritdoc />
    public async Task<bool> LinkExternalAccountAsync(Guid userId, string provider, string providerUserId)
    {
        var user = await _userManager.FindByIdAsync(userId.ToString());
        if (user == null)
        {
            _logger.LogWarning("EN: User not found / VI: Không tìm thấy user");
            return false;
        }

        var loginInfo = new UserLoginInfo(provider, providerUserId, provider);
        var result = await _userManager.AddLoginAsync(user, loginInfo);

        if (!result.Succeeded)
        {
            _logger.LogWarning(
                "EN: Failed to link external account / VI: Không thể liên kết tài khoản bên ngoài");
            return false;
        }

        return true;
    }

    /// <inheritdoc />
    public async Task<bool> UnlinkExternalAccountAsync(Guid userId, string provider)
    {
        var user = await _userManager.FindByIdAsync(userId.ToString());
        if (user == null)
        {
            _logger.LogWarning("EN: User not found / VI: Không tìm thấy user");
            return false;
        }

        // EN: Get the provider user ID
        // VI: Lấy provider user ID
        var logins = await _userManager.GetLoginsAsync(user);
        var login = logins.FirstOrDefault(l => l.LoginProvider == provider);

        if (login == null)
        {
            _logger.LogWarning(
                "EN: External login not found / VI: Không tìm thấy external login");
            return false;
        }

        var result = await _userManager.RemoveLoginAsync(user, provider, login.ProviderKey);
        return result.Succeeded;
    }

    /// <inheritdoc />
    public async Task<IEnumerable<string>> GetLinkedProvidersAsync(Guid userId)
    {
        var user = await _userManager.FindByIdAsync(userId.ToString());
        if (user == null)
        {
            return Enumerable.Empty<string>();
        }

        var logins = await _userManager.GetLoginsAsync(user);
        return logins.Select(l => l.LoginProvider);
    }
}
