package cn.reghao.tnb.account.app.service.impl;

import cn.reghao.jutil.jdk.result.Result;
import cn.reghao.jutil.jdk.result.ResultStatus;
import cn.reghao.jutil.jdk.security.RandomString;
import cn.reghao.jutil.jdk.string.StringRegexp;
import cn.reghao.tnb.account.api.constant.VerifyChannel;
import cn.reghao.tnb.account.api.dto.AdminCreateAccount;
import cn.reghao.tnb.account.app.model.dto.UserRegisterDto;
import cn.reghao.tnb.account.app.db.repository.AccountRepository;
import cn.reghao.tnb.account.app.model.po.UserAccountRole;
import cn.reghao.tnb.account.app.model.po.UserRegistry;
import cn.reghao.tnb.account.app.service.CodeService;
import cn.reghao.tnb.account.app.model.po.UserAccount;
import cn.reghao.tnb.account.app.service.AccountRegistryService;
import cn.reghao.tnb.account.app.service.PubkeyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;

/**
 * @author reghao
 * @date 2022-04-13 10:15:34
 */
@Slf4j
@Service
public class AccountRegistryServiceImpl implements AccountRegistryService {
    private final CodeService codeService;
    private final PasswordEncoder passwordEncoder;
    private final AccountRepository accountRepository;
    private final PubkeyService pubkeyService;
    private String avatarUrl;

    public AccountRegistryServiceImpl(CodeService codeService, PasswordEncoder passwordEncoder,
                                      AccountRepository accountRepository, PubkeyService pubkeyService) {
        this.codeService = codeService;
        this.passwordEncoder = passwordEncoder;
        this.accountRepository = accountRepository;
        this.pubkeyService = pubkeyService;
    }

    @PostConstruct
    public void setAvatarUrl() {
        String domain = accountRepository.getUserRegistry().getDomain();
        this.avatarUrl = String.format("//%s/dist/images/face.jpg", domain);
    }

    @Override
    public synchronized Result createAccount(UserRegisterDto userRegisterDto) {
        String captchaCode = userRegisterDto.getCaptchaCode();
        String savedCaptchaCode = codeService.getCaptcha();
        if (savedCaptchaCode == null) {
            return Result.fail("当前会话已过期, 请刷新页面后重新登入. 或者检查浏览器是否禁用了 cookie");
        } else if (!captchaCode.equalsIgnoreCase(savedCaptchaCode)) {
            return Result.fail("图形验证码不正确, 请刷新页面后重新获取");
        }

        String principal = userRegisterDto.getPrincipal();
        String verifyCode = userRegisterDto.getVerifyCode();
        String savedVerifyCode = codeService.getVerifyCode(VerifyChannel.registryChannel.getValue(), principal);
        if (savedVerifyCode == null) {
            return Result.fail("当前会话已过期, 请刷新页面后重新登入. 或者检查浏览器是否禁用了 cookie");
        } else if (!verifyCode.equalsIgnoreCase(savedVerifyCode)) {
            return Result.fail("短信验证码不正确, 请重新获取");
        }

        String email = null;
        String mobile = null;
        if (StringRegexp.matchEmail(principal)) {
            email = principal;
        } else if (StringRegexp.matchMobile(principal)) {
            mobile = principal;
        }

        String credential = userRegisterDto.getCredential();
        String decryptCredential;
        try {
            decryptCredential = pubkeyService.decrypt(credential);
        } catch (Exception e) {
            return Result.result(ResultStatus.FAIL, "密码不正确, 请刷新页面后重新注册");
        }

        long userId = accountRepository.getNextUserId();
        String salt = RandomString.getSalt(64);
        String encodedPassword = passwordEncoder.encode(decryptCredential + salt);
        UserAccount userAccount = new UserAccount(userId, email, mobile, encodedPassword, salt, avatarUrl);
        accountRepository.saveAccount(userAccount);
        return Result.result(ResultStatus.SUCCESS, "帐号已创建");
    }

    @Override
    public void createAccount(AdminCreateAccount adminCreateAccount) {
        String principal = adminCreateAccount.getUsername();
        String email = null;
        String mobile = null;
        if (StringRegexp.matchEmail(principal)) {
            email = principal;
        } else if (StringRegexp.matchMobile(principal)) {
            mobile = principal;
        }

        String decryptCredential = adminCreateAccount.getPassword();
        long userId = accountRepository.getNextUserId();
        String salt = RandomString.getSalt(64);
        String encodedPassword = passwordEncoder.encode(decryptCredential + salt);
        UserAccount userAccount = new UserAccount(userId, email, mobile, encodedPassword, salt, avatarUrl);
        accountRepository.saveAccount(userAccount);
    }

    @Override
    public UserAccount createAccount(String principal, String password) {
        String email = null;
        String mobile = null;
        if (StringRegexp.matchEmail(principal)) {
            email = principal;
        } else if (StringRegexp.matchMobile(principal)) {
            mobile = principal;
        }

        long userId = accountRepository.getNextUserId();
        UserAccount userAccount = new UserAccount(userId, email, mobile, avatarUrl);
        accountRepository.saveAccount(userAccount);
        return accountRepository.getUserAccountByMobile(mobile);
    }

    public Result getRegistryStatus() {
        UserRegistry userRegistry = accountRepository.getUserRegistry();
        if (!userRegistry.getEnabled()) {
            return Result.fail("系统当前未开放注册");
        }

        String rule = userRegistry.getRule();
        LocalDateTime localDateTime = LocalDateTime.now();
        return Result.success();
    }
}
