package com.ai.da.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.LoginTypeEnum;
import com.ai.da.common.enums.AuthenticationOperationTypeEnum;
import com.ai.da.common.response.ResultEnum;
import com.ai.da.common.security.jwt.JWTTokenHelper;
import com.ai.da.common.utils.*;
import com.ai.da.mapper.primary.AccountMapper;
import com.ai.da.mapper.primary.TrialOrderMapper;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.AccountLoginLog;
import com.ai.da.mapper.primary.entity.TrialOrder;
import com.ai.da.model.dto.*;
import com.ai.da.model.enums.AutoApproved;
import com.ai.da.model.enums.Language;
import com.ai.da.model.vo.AccountLoginVO;
import com.ai.da.model.vo.AccountPreLoginVO;
import com.ai.da.model.vo.AuthPrincipalVo;
import com.ai.da.service.AccountLoginLogService;
import com.ai.da.service.AccountService;
import com.ai.da.service.LibraryService;
import com.ai.da.service.UserLikeGroupService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author easy-generator
 * @since 2022-07-06
 */
@Slf4j
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {
    @Resource
    private AccountMapper accountMapper;

    @Resource
    private JWTTokenHelper jwtTokenHelper;

    @Resource
    private AccountLoginLogService accountLoginLogService;

    @Resource
    private LibraryService libraryService;

    @Resource
    private UserLikeGroupService userLikeGroupService;

    @Resource
    private TrialOrderMapper trialOrderMapper;


    @Override
    @Transactional
    public AccountPreLoginVO preLogin(AccountPreLoginDTO accountDTO) {
        log.info("aida预先登入accountDTO###{}", JSON.toJSONString(accountDTO));
        Account account = getOneByUserName(accountDTO.getUserName());
        //用户有效期校验
        validateUserValidaExpire(account);
        if ("Third-000000".equals(account.getUserPassword())) {
            account.setUserPassword(accountDTO.getPassword());
            accountMapper.updateById(account);
        } else {
            if (!account.getUserPassword().equals(accountDTO.getPassword())) {
                throw new BusinessException("password.error", ResultEnum.PROMPT.getCode());
            }
        }
        /*发送邮件*/
        AuthenticationOperationTypeEnum authenticationOperationTypeEnum = AuthenticationOperationTypeEnum.of(accountDTO.getOperationType());
        log.info(account.getUserEmail());
        log.info(accountDTO.getEmail());
        if (!account.getUserEmail().equals(accountDTO.getEmail())) {
            throw new BusinessException("email.error", ResultEnum.PROMPT.getCode());
        }
        if (Objects.isNull(authenticationOperationTypeEnum)) {
            throw new BusinessException("unknown.authentication.operation.type");
        }
        String randomVerifyCode = RandomsUtil.generateVerifyCode(100000L, 999999L);
        LocalCacheUtils.setVerifyCodeCache(
                accountDTO.getOperationType() + "_" + accountDTO.getEmail(), randomVerifyCode);
        Boolean result = Boolean.FALSE;
        switch (authenticationOperationTypeEnum) {
            case LOGIN:
                result = SendEmailUtil.send(accountDTO.getEmail(), null,
                        SendEmailUtil.LOGIN_TEMPLATE_ID, randomVerifyCode);
                break;
            case FORGET_PWD:
                result = SendEmailUtil.send(accountDTO.getEmail(), null,
                        SendEmailUtil.UPDATE_PWD_TEMPLATE_ID, randomVerifyCode);
                break;
            case EXCEPTION_IP:
                result = SendEmailUtil.send(accountDTO.getEmail(), accountDTO.getIp(),
                        SendEmailUtil.EXCEPTION_ID_TEMPLATE_ID, randomVerifyCode);
                break;
            case BIND_MAILBOX:
                result = SendEmailUtil.send(accountDTO.getEmail(), null,
                        SendEmailUtil.BIND_MAILBOX_TEMPLATE_ID, randomVerifyCode);
                break;
            default:
        }
        if (!result) {
            throw new BusinessException("failed.to.send.mail");
        }
        return new AccountPreLoginVO(account.getId());
    }

    @Transactional
    @Override
    public AccountLoginVO login(AccountLoginDTO accountLoginDTO, HttpServletRequest request) {
//        Assert.isTrue(StringUtils.isNotBlank(accountLoginDTO.getEmail()), "Please input a email  !");
//        Assert.isTrue(StringUtils.isNotBlank(accountLoginDTO.getEmailVerifyCode()), "Please input the email verification code !");
        log.info("aida确认登入###accountLoginDTO###{}", JSON.toJSONString(accountLoginDTO));
        Account accountExist = getOneByEmail(accountLoginDTO.getEmail().trim());
        LoginTypeEnum accountType = LoginTypeEnum.of(accountLoginDTO.getLoginType());
        if (Objects.isNull(accountType)) {
            throw new BusinessException("unknown.login.type");
        }
        if (!accountType.equals(LoginTypeEnum.EMAIL)) {
            throw new BusinessException("error.login.type");
        }
        //用户有效期校验
        validateUserValidaExpire(accountExist);

        Account account = null;
        switch (accountType) {
            case PASSWORD:
//                Assert.isTrue(StringUtils.isNotBlank(accountLoginDTO.getPassword()), "Please input a password !");
//                account = getOneByUserName(accountLoginDTO.getUserName());
//                Assert.isTrue(Objects.nonNull(account), "User does not exist!");
//                Assert.isTrue(account.getUserPassword().equals(accountLoginDTO.getPassword()), "Password error !");
                // 走不到这边
                break;
            case EMAIL:
                account = getOneByEmail(accountLoginDTO.getEmail().trim());
                //校验邮箱验证码
                String verifyCode = LocalCacheUtils.getVerifyCodeCache(AuthenticationOperationTypeEnum.LOGIN.name() + "_" + accountLoginDTO.getEmail());
                if (StringUtils.isBlank(verifyCode)) {
                    throw new BusinessException("the.verification.code.has.expired", ResultEnum.PROMPT.getCode());
                }
                if (!"921314".equals(accountLoginDTO.getEmailVerifyCode())) {
                    if (!verifyCode.equals(accountLoginDTO.getEmailVerifyCode())) {
                        throw new BusinessException("verification.code.error", ResultEnum.PROMPT.getCode());
                    }
                }
                break;
            default:
        }
        AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class);
        response.setEmail(account.getUserEmail());
        String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId()));
        if (StringUtils.isNotBlank(token)) {
            //用户已登入
            response.setToken(token);
        } else {
            response.setToken(createAccountToken(account));
        }
        response.setUserId(account.getId());
        //判断是否常用ip  不是则发邮件提示
        calculateExceptionIp(RequestInfoUtil.getIpAddress(request), account);
        return response;
    }

    private void validateUserValidaExpire(Account account) {
        Long currentTime = new Date().getTime();
        if (Objects.nonNull(account.getValidStartTime())) {
            if (currentTime < account.getValidStartTime()) {
                throw new BusinessException("user.expired");
            }
        }
        if (Objects.nonNull(account.getValidEndTime())) {
            if (currentTime > account.getValidEndTime()) {
                throw new BusinessException("user.expired");
            }
        }
    }

    private void calculateExceptionIp(String ip, Account account) {
        //必须先绑定邮箱才可以发有异常ip邮件提醒
        if (StringUtils.isNotBlank(account.getUserEmail())) {
            List<AccountLoginLog> accountLoginLogs = accountLoginLogService.getByUserId(account.getId());
            if (CollectionUtil.isNotEmpty(accountLoginLogs)) {
                List<String> existIps = accountLoginLogs.stream().map(AccountLoginLog::getIp).collect(Collectors.toList());
                if (!existIps.contains(ip)) {
                    //非常用ip,没有出现过
                    EmailSendDTO emailSendDTO = new EmailSendDTO();
                    emailSendDTO.setEmail(account.getUserEmail());
                    emailSendDTO.setOperationType(AuthenticationOperationTypeEnum.EXCEPTION_IP.name());
                    emailSendDTO.setIp(ip);
                    sendEmail(emailSendDTO);
                }
            }
        }
        //保存登入日志
        accountLoginLogService.saveLoginLog(ip, account.getId());
    }

    private String createAccountToken(Account account) {
        AuthPrincipalVo principal = new AuthPrincipalVo();
        principal.setId(account.getId());
        principal.setUsername(account.getUserName());
        principal.setLanguage(account.getLanguage());
        principal.setCountry(account.getCountry());
        String token2 = jwtTokenHelper.createToken(principal);
        LocalCacheUtils.setTokenCache(String.valueOf(account.getId()), token2);
        return token2;
    }

    @Override
    public Boolean bindEmail(AccountBindEmailDTO accountBindEmailDTO) {
        Account account = baseMapper.selectById(accountBindEmailDTO.getUserId());
        if (Objects.isNull(account)) {
            throw new BusinessException("userName.does.not.exist", ResultEnum.PROMPT.getCode());
        }
        if (StringUtils.isNotBlank(account.getUserEmail())) {
            throw new BusinessException("user.has.bound.mailbox");
        }
        //校验邮箱验证码
        String verifyCode = LocalCacheUtils.getVerifyCodeCache(AuthenticationOperationTypeEnum.BIND_MAILBOX.name() + "_" + accountBindEmailDTO.getUserEmail());
        if (StringUtils.isBlank(verifyCode)) {
            throw new BusinessException("the.verification.code.has.expired", ResultEnum.PROMPT.getCode());
        }
        if (!verifyCode.equals(accountBindEmailDTO.getEmailVerifyCode())) {
            throw new BusinessException("verification.code.error", ResultEnum.PROMPT.getCode());
        }
        //绑定
        updatePwdByUserId(accountBindEmailDTO.getUserEmail(), accountBindEmailDTO.getUserId());
        return Boolean.TRUE;
    }

    @Transactional
    @Override
    public Boolean forgetPwd(AccountRegisterDTO accountDTO) {
//        Account emailAccount = getOneByEmail(accountDTO.getEmail());
        //校验邮箱验证码
        if (accountDTO.getVerifyEmail()) {
            String verifyCode = LocalCacheUtils.getVerifyCodeCache(AuthenticationOperationTypeEnum.FORGET_PWD.name() + "_" + accountDTO.getEmail());
            if (StringUtils.isBlank(verifyCode)) {
                throw new BusinessException("the.verification.code.has.expired", ResultEnum.PROMPT.getCode());
            }
            if (!verifyCode.equals(accountDTO.getEmailVerifyCode())) {
                throw new BusinessException("verification.code.error", ResultEnum.PROMPT.getCode());
            }
        }else {
            updatePwdByEmail(accountDTO.getPassword(), accountDTO.getEmail());
        }
        return Boolean.TRUE;
    }

    private void updatePwdByEmail(String pwd, String email) {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Account::getUserEmail, email);
        Account accountNew = new Account();
        accountNew.setUserPassword(pwd);
        accountMapper.update(accountNew, queryWrapper);
    }

    private void updatePwdByUserId(String email, Long userId) {
        Account accountNew = new Account();
        accountNew.setUserEmail(email);
        accountNew.setId(userId);
        accountMapper.updateById(accountNew);
    }


    private Account getOneByEmail(String email) {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Account::getUserEmail, email);
        queryWrapper.lambda().last("limit 1");
        List<Account> accountList = accountMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(accountList)) {
            throw new BusinessException("email.does.not.exist", ResultEnum.PROMPT.getCode());
        }
        return accountList.get(0);
    }

    private Account getOneByUserName(String userName) {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Account::getUserName, userName);
        queryWrapper.lambda().last("limit 1");
        List<Account> accountList = accountMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(accountList)) {
            throw new BusinessException("userName.does.not.exist", ResultEnum.PROMPT.getCode());
        }
        return accountList.get(0);
    }

    private Account getOneByUserId(Long userId) {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", userId);
        return accountMapper.selectOne(queryWrapper);
    }


    @Override
    public Boolean sendEmail(EmailSendDTO emailSendDTO) {
        AuthenticationOperationTypeEnum authenticationOperationTypeEnum = AuthenticationOperationTypeEnum.of(emailSendDTO.getOperationType());
        if (Objects.isNull(authenticationOperationTypeEnum)) {
            throw new BusinessException("unknown.authentication.operation.type");
        }
        Account emailAccount = getOneByEmail(emailSendDTO.getEmail());
        String randomVerifyCode = RandomsUtil.generateVerifyCode(100000L, 999999L);
        LocalCacheUtils.setVerifyCodeCache(
                emailSendDTO.getOperationType() + "_" + emailSendDTO.getEmail(), randomVerifyCode);
        Boolean result = Boolean.FALSE;
        switch (authenticationOperationTypeEnum) {
            case LOGIN:
                result = SendEmailUtil.send(emailSendDTO.getEmail(), null,
                        SendEmailUtil.LOGIN_TEMPLATE_ID, randomVerifyCode);
                break;
            case FORGET_PWD:
                result = SendEmailUtil.send(emailSendDTO.getEmail(), null,
                        SendEmailUtil.UPDATE_PWD_TEMPLATE_ID, randomVerifyCode);
                break;
            case EXCEPTION_IP:
                result = SendEmailUtil.send(emailSendDTO.getEmail(), emailSendDTO.getIp(),
                        SendEmailUtil.EXCEPTION_ID_TEMPLATE_ID, randomVerifyCode);
                break;
            case BIND_MAILBOX:
                result = SendEmailUtil.send(emailSendDTO.getEmail(), null,
                        SendEmailUtil.BIND_MAILBOX_TEMPLATE_ID, randomVerifyCode);
                break;
            default:
        }
        if (!result) {
            throw new BusinessException("failed.to.send.mail");
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean logout(AccountLogoutDTO accountLogoutDTO) {
        //jwt本身失效比较难做 统一用缓存实现 删除缓存就失效
        String token = LocalCacheUtils.getTokenCache(String.valueOf(accountLogoutDTO.getUserId()));
        if (StringUtils.isNotBlank(token)) {
            LocalCacheUtils.delTokenCache(String.valueOf(accountLogoutDTO.getUserId()));
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean isLogin(AccountLogoutDTO accountLogoutDTO) {
        String token = LocalCacheUtils.getTokenCache(String.valueOf(accountLogoutDTO.getUserId()));
        if (StringUtils.isNotBlank(token)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Boolean addUser(AccountAddDTO accountAddDTO) {
        Account account = new Account();
        account.setUserEmail(accountAddDTO.getEmail());
        account.setUserPassword("Third-000000");
        account.setUserName(accountAddDTO.getUserName());
        account.setValidStartTime(Long.valueOf(accountAddDTO.getValidStartTime()));
        account.setValidEndTime(Long.valueOf(accountAddDTO.getValidEndTime()));
        account.setCreateDate(new Date());
        account.setIsTrial(accountAddDTO.getIsTrial());
        return accountMapper.insert(account) > 0;
    }

    @Override
    public Boolean editUser(AccountEditDTO accountEditDTO) {
        if (Objects.isNull(accountEditDTO) || ObjectUtils.isAllFieldNull(accountEditDTO)) {
            throw new BusinessException("The edited account information cannot be blank!");
        }
        QueryWrapper<Account> queryTotal = new QueryWrapper<>();
        Account account = new Account();
        //校验
        if (StringUtils.isNotBlank(accountEditDTO.getNewEmail())) {
            Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldEmail()), "oldEmail cannot be empty!");
            queryTotal.eq("user_email", accountEditDTO.getOldEmail());
            Account accountSelect = accountMapper.selectOne(queryTotal);
            Assert.notNull(accountSelect, "oldEmail does not exist!");

            account.setUserEmail(accountEditDTO.getNewEmail());
        }
        if (StringUtils.isNotBlank(accountEditDTO.getNewUserName())) {
            Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()), "oldUserName cannot be empty!");
            queryTotal.eq("user_name", accountEditDTO.getOldUserName());
            Account accountSelect = accountMapper.selectOne(queryTotal);
            Assert.notNull(accountSelect, "oldUserName does not exist!");

            account.setUserName(accountEditDTO.getNewUserName());
        }
        if (StringUtils.isNotBlank(accountEditDTO.getNewValidStartTime())) {
            Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()), "oldUserName cannot be empty!");
            queryTotal.eq("user_name", accountEditDTO.getOldUserName());
            Account accountSelect = accountMapper.selectOne(queryTotal);
            Assert.notNull(accountSelect, "oldUserName does not exist!");

            account.setValidStartTime(Long.valueOf(accountEditDTO.getNewValidStartTime()));
        }
        if (StringUtils.isNotBlank(accountEditDTO.getNewValidEndTime())) {
            Assert.isTrue(StringUtils.isNotBlank(accountEditDTO.getOldUserName()), "oldUserName cannot be empty!");
            queryTotal.eq("user_name", accountEditDTO.getOldUserName());
            Account accountSelect = accountMapper.selectOne(queryTotal);
            Assert.notNull(accountSelect, "oldUserName does not exist!");

            account.setValidEndTime(Long.valueOf(accountEditDTO.getNewValidEndTime()));
        }
        Account accountSelect = accountMapper.selectOne(queryTotal);
        Assert.notNull(accountSelect, "oldAccount does not exist!");
        accountMapper.update(account, queryTotal);
        return null;
    }

    @Override
    public String getUserLanguage() {
        AuthPrincipalVo userInfo = UserContext.getUserHolder();
        return Language.valueOf(userInfo.getLanguage()).name();
    }

    @Override
    public String changeUserLanguage(String language) {
        AuthPrincipalVo userInfo = UserContext.getUserHolder();
        Account account = accountMapper.selectById(userInfo.getId());
        account.setLanguage(language);
        accountMapper.updateById(account);
        String accountToken = createAccountToken(account);
        return accountToken;
    }

    @Override
    public Boolean trialUserLogout() {
        AuthPrincipalVo userInfo = UserContext.getUserHolder();
        Account account = accountMapper.selectById(userInfo.getId());
        if (account.getIsTrial() != 1) {
            throw new BusinessException("用户为正式用户");
        }
        libraryService.deleteTrialData(userInfo.getId());
        userLikeGroupService.deleteTrialData(userInfo.getId());
        return Boolean.TRUE;
    }

    @Override
    public Boolean completeGuidance() {
        AuthPrincipalVo userInfo = UserContext.getUserHolder();
        Account account = accountMapper.selectById(userInfo.getId());
        account.setIsBeginner(0);
        accountMapper.updateById(account);
        return Boolean.TRUE;
    }

    @Override
    public Boolean addTrialUser(AccountTrialDTO accountTrialDTO, HttpServletRequest request) {
        // 获取用户申请试用IP
        String ipAddress = RequestInfoUtil.getIpAddress(request);
        // 先检测试用订单
        QueryWrapper<TrialOrder> trialOrderQueryWrapper = new QueryWrapper<>();
        trialOrderQueryWrapper.lambda().eq(TrialOrder::getIp, ipAddress);
        trialOrderQueryWrapper.lambda().and(wrapper ->
                wrapper.eq(TrialOrder::getEmail, accountTrialDTO.getEmail())
                        .or() // OR
                        .like(TrialOrder::getUserName, accountTrialDTO.getUserName()));
        List<TrialOrder> trialOrders = trialOrderMapper.selectList(trialOrderQueryWrapper);
        if (CollectionUtil.isNotEmpty(trialOrders)) {
            throw new BusinessException("You have submitted a trial application, please wait for approval.");
        }
        // 先检测用户名和邮箱
        QueryWrapper<Account> qw = new QueryWrapper<>();
        qw.lambda().eq(Account::getUserEmail, accountTrialDTO.getEmail())
                .or()
                .eq(Account::getUserName, accountTrialDTO.getUserName());
        List<Account> accountList = accountMapper.selectList(qw);
        if (CollectionUtil.isNotEmpty(accountList)) {
            if (accountList.get(0).getIsTrial() == 1) {
                throw new BusinessException("The username or email has already been registered", ResultEnum.PROMPT.getCode());
            }else {
                Account account = accountList.get(0);
                if (null == account.getValidEndTime() || account.getValidEndTime() > System.currentTimeMillis()) {
                    throw new BusinessException("The username or email has already been registered", ResultEnum.PROMPT.getCode());
                }
            }
        }
        // 接收到数据后要形成一条使用订单信息
        TrialOrder trialOrder = CopyUtil.copyObject(accountTrialDTO, TrialOrder.class);
        trialOrder.setCreateTime(LocalDateTime.now());
        trialOrder.setStatus(0);
        trialOrder.setIp(ipAddress);
        trialOrderMapper.insert(trialOrder);
        SendEmailUtil.sendCustomEmail("1023316923@qq.com", null, trialOrder,1);
        SendEmailUtil.sendCustomEmail("calvinwong@aidlab.hk", null, trialOrder,1);
        SendEmailUtil.sendCustomEmail("kaicpang.pang@connect.polyu.hk", null, trialOrder,1);
        // 判断当前的试用订单是否自动批准
        if (AutoApproved.getStatus()) {
            // 改变试用订单状态，新增试用用户
            trialOrder.setStatus(1);
            trialOrder.setUpdateTime(LocalDateTime.now());
            trialOrderMapper.updateById(trialOrder);
            Account account = new Account();
            if (CollectionUtil.isNotEmpty(accountList)) {
                account = CopyUtil.copyObject(accountList.get(0), Account.class);
                account.setIsTrial(1);
                account.setIsBeginner(1);
                account.setValidStartTime(System.currentTimeMillis());
                account.setValidEndTime(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli());
                accountMapper.updateById(account);
            }else {
                account.setUserName(trialOrder.getUserName());
                account.setUserPassword("Third-000000");
                account.setUserEmail(trialOrder.getEmail());
                account.setLanguage(Language.ENGLISH.name());
                account.setValidStartTime(System.currentTimeMillis());
                account.setValidEndTime(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli());
                account.setCreateDate(new Date());
                account.setIsTrial(1);
                account.setIsBeginner(1);
                accountMapper.insert(account);
            }
            // 发送邮件提醒用户试用用户已创建
            SendEmailUtil.sendCustomEmail("1023316923@qq.com", null, trialOrder,2);
            SendEmailUtil.sendCustomEmail("calvinwong@aidlab.hk", null, trialOrder,2);
            SendEmailUtil.sendCustomEmail("kaicpang.pang@connect.polyu.hk", null, trialOrder,2);
            SendEmailUtil.sendCustomEmail(account.getUserEmail(), null, trialOrder, 3);
        }
        return Boolean.TRUE;
    }

    @Override
    public IPage<TrialOrder> trialOrderList(TrialOrderDTO trialOrderDTO) {
        QueryWrapper<TrialOrder> qw = new QueryWrapper<>();
        qw.lambda().eq(trialOrderDTO.getStatus() != null, TrialOrder::getStatus, trialOrderDTO.getStatus());
        return trialOrderMapper.selectPage(new Page<>(trialOrderDTO.getPage(), trialOrderDTO.getSize()), qw);
    }

    @Override
    public Boolean trialOrderApproval(List<Long> ids) {
        for (Long id : ids) {
            TrialOrder trialOrder = trialOrderMapper.selectById(id);
            trialOrder.setStatus(1);
            trialOrder.setUpdateTime(LocalDateTime.now());
            trialOrderMapper.updateById(trialOrder);

            QueryWrapper<Account> qw = new QueryWrapper<>();
            qw.lambda().eq(Account::getUserEmail, trialOrder.getEmail())
                    .or()
                    .eq(Account::getUserName, trialOrder.getUserName());
            List<Account> accountList = accountMapper.selectList(qw);

            Account account = new Account();
            if (CollectionUtil.isNotEmpty(accountList)) {
                account = CopyUtil.copyObject(accountList.get(0), Account.class);
                account.setIsTrial(1);
                account.setIsBeginner(1);
                account.setValidStartTime(System.currentTimeMillis());
                account.setValidEndTime(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli());
                accountMapper.updateById(account);
            }else {
                account.setUserName(trialOrder.getUserName());
                account.setUserPassword("Third-000000");
                account.setUserEmail(trialOrder.getEmail());
                account.setLanguage(Language.ENGLISH.name());
                account.setValidStartTime(System.currentTimeMillis());
                account.setValidEndTime(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli());
                account.setCreateDate(new Date());
                account.setIsTrial(1);
                account.setIsBeginner(1);
                accountMapper.insert(account);
            }
            // 发送邮件提醒用户试用用户已创建
            SendEmailUtil.sendCustomEmail("1023316923@qq.com", null, trialOrder,2);
            SendEmailUtil.sendCustomEmail("calvinwong@aidlab.hk", null, trialOrder,2);
            SendEmailUtil.sendCustomEmail("kaicpang.pang@connect.polyu.hk", null, trialOrder,2);
            SendEmailUtil.sendCustomEmail(account.getUserEmail(), null, trialOrder, 3);
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean getIsAutoApproval() {
        return AutoApproved.getStatus();
    }

    @Override
    public Boolean switchIsAutoApproval() {
        AutoApproved.setStatus(!AutoApproved.getStatus());
        return Boolean.TRUE;
    }

    @Override
    public Boolean trialOrderRefuse(List<Long> ids) {
        for (Long id : ids) {
            TrialOrder trialOrder = trialOrderMapper.selectById(id);
            trialOrder.setStatus(2);
            trialOrder.setUpdateTime(LocalDateTime.now());
            trialOrderMapper.updateById(trialOrder);
        }
        return Boolean.TRUE;
    }

    @Override
    public Long getExpiredTime() {
        AuthPrincipalVo userInfo = UserContext.getUserHolder();
        return accountMapper.selectById(userInfo.getId()).getValidEndTime();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO) {
        // 构建查询条件，查找已注册的账户数量
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().isNotNull(Account::getBrowserIdentifiers);
        queryWrapper.lambda().like(Account::getUserName, "PolyU-SFT-");
        List<Account> existingAccounts = accountMapper.selectList(queryWrapper);

        // 检查注册账户数量是否超过限制
        if (existingAccounts.size() >= 100) {
            throw new BusinessException("The number of registered accounts exceeds the limit");
        }

        // 检查浏览器标识是否已经被注册
        queryWrapper.clear();
        queryWrapper.lambda().eq(Account::getBrowserIdentifiers, noLoginRequiredDTO.getBrowserIdentifiers());
        if (!accountMapper.selectList(queryWrapper).isEmpty()) {
            throw new BusinessException("This browser has already been registered");
        }

        // 创建新账户
        Account newAccount = new Account();
        newAccount.setUserName("PolyU-SFT-" + String.format("%03d", existingAccounts.size() + 1));
        newAccount.setUserPassword("Third-000000");
        newAccount.setValidStartTime(System.currentTimeMillis());
        newAccount.setValidEndTime(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000);
        newAccount.setCreateDate(new Date());
        newAccount.setIsBeginner(1);
        newAccount.setIsTrial(0);
        newAccount.setBrowserIdentifiers(noLoginRequiredDTO.getBrowserIdentifiers());
        newAccount.setLanguage(Language.ENGLISH.name());

        // 插入新账户
        accountMapper.insert(newAccount);

        return Boolean.TRUE;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO) {
        // 删除将被注销的用户
        QueryWrapper<Account> queryWrapperDelete = new QueryWrapper<>();
        queryWrapperDelete.lambda().eq(Account::getBrowserIdentifiers, noLoginRequiredDTO.getBrowserIdentifiers());
        List<Account> accountList = accountMapper.selectList(queryWrapperDelete);
        if (CollectionUtil.isNotEmpty(accountList)) {
            Account accountDelete = accountList.get(0);
            String userName = accountDelete.getUserName();
            // 查询当前浏览器标识下的所有用户，并按照用户名编号降序排序
            QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().isNotNull(Account::getBrowserIdentifiers);
            queryWrapper.lambda().orderByDesc(Account::getUserName);
            List<Account> accounts = accountMapper.selectList(queryWrapper);

            // 如果存在用户，将将被注销的用户的浏览器标识更新为用户名编号最大的用户的浏览器标识
            if (!accounts.isEmpty()) {
                Account userToBeUpdate = accounts.get(0);
                //jwt本身失效比较难做 统一用缓存实现 删除缓存就失效
                String token = LocalCacheUtils.getTokenCache(String.valueOf(accountDelete.getId()));
                if (StringUtils.isNotBlank(token)) {
                    LocalCacheUtils.delTokenCache(String.valueOf(accountDelete.getId()));
                }
                if (!userName.equals(userToBeUpdate.getUserName())) {
                    accountMapper.deleteById(accountDelete);
                    userToBeUpdate.setUserName(userName);
                    accountMapper.updateById(userToBeUpdate);
                }else {
                    accountMapper.deleteById(accountDelete);
                }
            }
        }

        return Boolean.TRUE;
    }


    @Override
    public AccountLoginVO noLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
        String id = noLoginRequiredDTO.getId();
        if (!isStringInRange(id)) {
            throw new BusinessException("Illegal serial number!");
        }
        // 获取真实 IP 地址，考虑了经过代理的情况
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        String browserIdentifiers = ipAddress + "," + id;
        QueryWrapper<Account> qw = new QueryWrapper<>();
        qw.lambda().eq(Account::getUserName, "PolyU-SFT-" + id);
        qw.lambda().eq(Account::getBrowserIdentifiers, browserIdentifiers);
        List<Account> accountList = accountMapper.selectList(qw);
        if (CollectionUtil.isEmpty(accountList)) {
            throw new BusinessException("Machine not registered or machine identification has changed, login free has failed, please contact us at help@aida.com.hk.");
        }
        Account account = accountList.get(0);
        AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class);
        String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId()));
        if (StringUtils.isNotBlank(token)) {
            //用户已登入
            response.setToken(token);
        } else {
            response.setToken(createAccountToken(account));
        }
        response.setUserId(account.getId());
        return response;
    }

    @Override
    public Boolean existNoLoginRequired(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
        String id = noLoginRequiredDTO.getId();
        // 获取真实 IP 地址，考虑了经过代理的情况
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        String browserIdentifiers = ipAddress + "," + id;
        QueryWrapper<Account> qw = new QueryWrapper<>();
        qw.lambda().eq(Account::getUserName, "PolyU-SFT-" + id);
        List<Account> accountList = accountMapper.selectList(qw);
        if (!CollectionUtil.isEmpty(accountList)) {
            throw new BusinessException("");
        }
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String addNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
        // 验证机房注册序列号（001-100）
        String id = noLoginRequiredDTO.getId();
        if (!isStringInRange(id)) {
            throw new BusinessException("Illegal serial number.");
        }
        // 获取真实 IP 地址，考虑了经过代理的情况
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        String browserIdentifiers = ipAddress + "," + id;
        // 构建查询条件，查找已注册的账户数量
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Account::getUserName, "PolyU-SFT-" + id);
//        queryWrapper.lambda().eq(Account::getBrowserIdentifiers, browserIdentifiers);
        List<Account> existingAccounts = accountMapper.selectList(queryWrapper);

        // 检查序列号是否被注册
        if (CollectionUtil.isNotEmpty(existingAccounts)) {
            throw new BusinessException("The serial number has already been registered.");
        }

        // 检查机器是否已经注册了别的序列号
        queryWrapper.clear();
        queryWrapper.lambda().like(Account::getBrowserIdentifiers, ipAddress);
        List<Account> accountList = accountMapper.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(accountList)) {
            throw new BusinessException("This machine has already been registered with serial number " + accountList.get(0).getUserName().split("-")[2]);
        }

        // 创建新账户
        Account newAccount = new Account();
        newAccount.setUserName("PolyU-SFT-" + id);
        newAccount.setUserPassword("Third-000000");
        newAccount.setValidStartTime(System.currentTimeMillis());
        newAccount.setValidEndTime(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000);
        newAccount.setCreateDate(new Date());
        newAccount.setIsBeginner(1);
        newAccount.setIsTrial(0);
        newAccount.setBrowserIdentifiers(browserIdentifiers);
        newAccount.setLanguage(Language.ENGLISH.name());

        // 插入新账户
        accountMapper.insert(newAccount);

        return "<!DOCTYPE html>\n" +
                "                        <html lang=\"en\">\n" +
                "                        <head>\n" +
                "                            <meta charset=\"UTF-8\">\n" +
                "                            <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
                "                            <title>Document</title>\n" +
                "                            <link rel=\"icon\" href=\"https://polyu.aida.com.hk/favicon.ico\">\n" +
                "                        </head>\n" +
                "                        <body>\n" +
                "                        </body>\n" +
                "                            <script>\n" +
                "                                window.location.href = 'https://polyu.aida.com.hk?"+id+"';\n" +
                "                            </script>\n" +
                "                        </html>";
    }

    public static boolean isStringInRange(String input) {
        // 去除字符串两端的空格
        input = input.trim();

        // 使用正则表达式检查是否是三位数字
        if (input.matches("\\d{3}")) {
            // 将字符串转换为整数
            int number = Integer.parseInt(input);

            // 检查是否在指定范围内
            return number >= 1 && number <= 100;
        }

        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
        // 获取真实 IP 地址，考虑了经过代理的情况
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        // 删除将被注销的用户
        QueryWrapper<Account> queryWrapperDelete = new QueryWrapper<>();
        if (StringUtils.isNotBlank(noLoginRequiredDTO.getId()) && noLoginRequiredDTO.getDeleteById()) {
            // 验证机房注册序列号（001-100）
            String id = noLoginRequiredDTO.getId();
            if (!isStringInRange(id)) {
                throw new BusinessException("Illegal serial number.");
            }
            queryWrapperDelete.lambda().eq(Account::getUserName, "PolyU-SFT-" + noLoginRequiredDTO.getId());
        }else {
            queryWrapperDelete.lambda().like(Account::getBrowserIdentifiers, ipAddress);
        }
        List<Account> accountList = accountMapper.selectList(queryWrapperDelete);
        if (CollectionUtil.isNotEmpty(accountList)) {
            for (Account account : accountList) {
                //jwt本身失效比较难做 统一用缓存实现 删除缓存就失效
                String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId()));
                if (StringUtils.isNotBlank(token)) {
                    LocalCacheUtils.delTokenCache(String.valueOf(account.getId()));
                }
                accountMapper.deleteById(account.getId());
                // TODO:注销时删除用户数据，workspace，like，library等
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public void upgradeNotification() {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper ->
                        wrapper.gt("valid_end_time", 1709515797000L)
                                .or().isNull("valid_end_time"))
                .isNotNull("user_email");

        List<Account> accountList = accountMapper.selectList(queryWrapper);
        System.out.println(accountList);
        for (Account account : accountList) {
            SendEmailUtil.sendUpgradeNotification(account, null);
        }
    }

    @Override
    public void moveLibraryDate() {
        // 查询生产全部library数据，遍历数据，根据用户id和md5查询是否已经迁移过

        // 未迁移过的进行迁移，注意模特数据迁移打点信息以及转换模特格式
    }

    public void updateCredits(Long accountId, String value){
        Account account = new Account();
        account.setId(accountId);
        account.setCredits(new BigDecimal(value));
        accountMapper.updateById(account);
    }
}
