package com.zhiqiyun.open.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhiqiyun.open.core.enmus.AccountType;
import com.zhiqiyun.open.core.enmus.PasswordType;
import com.zhiqiyun.open.core.enmus.UserState;
import com.zhiqiyun.open.core.mapper.UserBaseInfoMapper;
import com.zhiqiyun.open.core.mapper.UserLoginAccountMapper;
import com.zhiqiyun.open.core.mapper.UserPasswordMapper;
import com.zhiqiyun.open.core.models.user.UserBaseInfo;
import com.zhiqiyun.open.core.models.user.UserLoginAccount;
import com.zhiqiyun.open.core.models.user.UserPassword;
import com.zhiqiyun.open.core.service.Ip2RegionService;
import com.zhiqiyun.open.core.service.OauthService;
import com.zhiqiyun.open.core.service.SequenceService;
import com.zhiqiyun.open.core.service.UserBaseInfoService;
import com.zhiqiyun.open.exception.ServiceException;
import com.zhiqiyun.open.utils.DateUtil;
import com.zhiqiyun.open.utils.RandomUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

/**
 * @author jtoms
 */
@Service
public class UserBaseInfoServiceImpl extends ServiceImpl<UserBaseInfoMapper, UserBaseInfo> implements UserBaseInfoService {

    @Autowired
    private UserLoginAccountMapper userLoginAccountMapper;

    @Autowired
    private UserPasswordMapper userPasswordMapper;

    @Autowired
    private OauthService oauthService;

    @Autowired
    private SequenceService sequenceService;

    @Autowired
    private Ip2RegionService ip2RegionService;

    @Override
    public UserLoginAccount findLoginAccount(String loginAccount, AccountType accountType) {
        QueryWrapper<UserLoginAccount> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isBlank(loginAccount)) {
            return null;
        }
        queryWrapper.eq("login_account", loginAccount);
        if (accountType != null) {
            queryWrapper.eq("account_type", accountType);
        }
        queryWrapper.last("limit 1");
        return this.userLoginAccountMapper.selectOne(queryWrapper);
    }

    @Override
    public UserPassword findPassword(Long uid, PasswordType passwordType) {
        String id = DigestUtils.md5Hex(String.format("%s@%s", passwordType.name(), uid));
        return this.userPasswordMapper.selectById(id);
    }

    @Override
    public List<String> findUserAuthorities(Long uid) {
        return this.baseMapper.findUserAuthorities(uid);
    }

    @Override
    public void updatePassword(Long uid, String password, String salt, PasswordType passwordType) {
        UserPassword userPassword = new UserPassword(uid, password, salt, passwordType);
        this.userPasswordMapper.insertOrUpdatePassword(userPassword);
    }

    @Override
    public void updateBaseInfo(Long uid, UserBaseInfo userBaseInfo) {
        userBaseInfo.setId(uid);
        this.baseMapper.updateById(userBaseInfo);
    }

    @Override
    public void updateLoginAccount(Long uid, String account, AccountType accountType) {
        UserLoginAccount loginAccount = new UserLoginAccount(uid, account, accountType);
        userLoginAccountMapper.insertOrUpdate(loginAccount);
    }

    @Override
    public List<Map<String, Object>> findSelectAccounts(String searchKey) {
        return this.baseMapper.findSelectAccounts(searchKey);
    }

    @Override
    public List<UserLoginAccount> findLoginAccounts(Long uid) {
        QueryWrapper<UserLoginAccount> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid", uid);
        return this.userLoginAccountMapper.selectList(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public String insertOrUpdate(UserBaseInfo userInfo, List<UserLoginAccount> loginAccounts, List<Long> listRoles) throws ServiceException {
        try {
            String loginPassword = null;
            if (userInfo.getId() == null) {
                Long uid = this.sequenceService.nextId();
                userInfo.setId(uid);
                userInfo.setState(UserState.normal);
                userInfo.setRegisterTime(DateUtil.current());
                if (StringUtils.isBlank(userInfo.getAvatar())) {
                    userInfo.setAvatar("");
                }
                loginPassword = RandomUtil.get(6);
                this.baseMapper.insert(userInfo);
            } else {
                this.updateById(userInfo);
            }

            userLoginAccountMapper.deleteByUid(userInfo.getId());
            for (UserLoginAccount loginAccount : loginAccounts) {
                loginAccount.setUid(userInfo.getId());
                userLoginAccountMapper.insertOrUpdate(loginAccount);
            }

            if (StringUtils.isNotBlank(loginPassword)) {
                String salt = RandomUtil.getSalt();
                String secretPassword = this.oauthService.generatePassword(loginPassword, salt);

                UserPassword userPassword = new UserPassword(userInfo.getId(), secretPassword, salt, PasswordType.login);
                this.userPasswordMapper.insertOrUpdatePassword(userPassword);
            }

            baseMapper.deleteRoles(userInfo.getId());
            if (listRoles != null && listRoles.size() > 0) {
                baseMapper.insertRoles(userInfo.getId(), listRoles);
            }

            return loginPassword;
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

//    @Override
//    public void insertLoginLog(UserLoginLog userLoginLog) {
//        try {
//            userLoginLog.setLoginLocal(this.ip2RegionService.getRegion(userLoginLog.getLoginIp()));
//        } finally {
//            userBaseInfoMapper.insertLoginLog(userLoginLog);
//        }
//    }
//
//    @Override
//    public PageResult<UserLoginLog> findLoginLogPage(PageBounds bounds, Map<String, Object> queryWrapper) {
//        List<UserLoginLog> listData = userBaseInfoMapper.findLoginLogPage(bounds, queryWrapper);
//        return bounds.newPageResult(listData);
//    }
}
