package cn.hanghui.outapi.platform.tenant.service.impl;

import cn.hanghui.outapi.platform.common.config.JwtConfig;
import cn.hanghui.outapi.platform.common.entity.po.Account;
import cn.hanghui.outapi.platform.common.entity.po.AccountAuthConfig;
import cn.hanghui.outapi.platform.common.entity.rest.RestResult;
import cn.hanghui.outapi.platform.common.exception.BusinessException;
import cn.hanghui.outapi.platform.common.mapper.AccountAuthConfigMapper;
import cn.hanghui.outapi.platform.common.mapper.AccountMapper;
import cn.hanghui.outapi.platform.common.utils.PasswordUtils;
import cn.hanghui.outapi.platform.common.utils.Preconditions;
import cn.hanghui.outapi.platform.tenant.entity.dto.account.AccountDto;
import cn.hanghui.outapi.platform.tenant.entity.dto.account.AccountSearch;
import cn.hanghui.outapi.platform.tenant.entity.dto.account.AccountVo;
import cn.hanghui.outapi.platform.tenant.entity.enums.AccountTypeEnum;
import cn.hanghui.outapi.platform.tenant.entity.po.Purchaser;
import cn.hanghui.outapi.platform.tenant.mapper.PurchaserMapper;
import cn.hanghui.outapi.platform.tenant.service.AccountService;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author shisl
 * @package cn.hanghui.outapi.platform.tenant.service.impl
 * @class AccountServiceImpl
 * @date 2024/7/1 下午4:35
 * @description
 */
@Slf4j
@Service
public class AccountServiceImpl implements AccountService {

    @Resource
    private AccountMapper accountMapper;

    @Resource
    private PurchaserMapper purchaserMapper;

    @Resource
    private AccountAuthConfigMapper accountAuthConfigMapper;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public RestResult<Boolean> add(AccountDto dto) {
        checkAccountDto(dto);
        if (Preconditions.isBlank(dto.getId())) {
            addAccount(dto);
        } else {
            updateAccount(dto);
        }
        return RestResult.ok(true);
    }

    private void checkAccountDto(AccountDto dto) {
        if (Preconditions.isBlank(dto)) {
            throw new BusinessException("参数不能为空");
        }

        if (Preconditions.isBlank(dto.getId())
                && (Preconditions.isBlank(dto.getName())
                || Preconditions.isBlank(dto.getPassword())
                || Preconditions.isBlank(dto.getPurchaserId()))) {//新增
            throw new BusinessException("参数有误，添加失败");
        }

        if (Preconditions.isNotBlank(dto.getId())
                && (Preconditions.isBlank(dto.getName())
                || Preconditions.isBlank(dto.getPurchaserId()))) {//编辑
            throw new BusinessException("参数有误，编辑失败");
        }

        if (Preconditions.isNotBlank(dto.getHhAromeSwitch())
                && dto.getHhAromeSwitch()
                && Preconditions.isBlank(dto.getDeviceConfig())
                && Preconditions.isBlank(dto.getSystemConfig())) {
            throw new BusinessException("HHArome参数有误");
        }

        if (Preconditions.isNotBlank(dto.getDeviceConfig())) {
            dto.getDeviceConfig().forEach(item -> {
                if (Preconditions.isNotBlank(item.getModuleSwitch())
                        && item.getModuleSwitch()
                        && (Preconditions.isBlank(item.getModuleType())
                        || Preconditions.isBlank(item.getModuleValues()))) {
                    throw new BusinessException("设备基本信息配置有误");
                }
            });
        }

    }

    private void updateAccount(AccountDto dto) {
        Account idAccount = accountMapper.selectById(dto.getId());
        if (Preconditions.isBlank(idAccount)) {
            throw new BusinessException(String.format("账号【%s】不存在", dto.getId()));
        }
        String oldName = idAccount.getName();
        LambdaQueryWrapper<Account> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Account::getName, dto.getName()).eq(Account::getIsDeleted, Boolean.FALSE);
        Account nameAccount = accountMapper.selectOne(wrapper);
        if (Preconditions.isNotBlank(nameAccount) && nameAccount.getId().longValue() != dto.getId().longValue()) {
            throw new BusinessException(String.format("账号名【%s】已存在", dto.getName()));
        }
        if (Preconditions.isNotBlank(dto.getPassword())) {
            idAccount.setPassword(PasswordUtils.passwd(dto.getPassword()));
        }
        if (Preconditions.isNotBlank(dto.getName())) {
            idAccount.setName(dto.getName());
        }
        idAccount.setUpdateTime(new Date());
        accountMapper.updateById(idAccount);
        //清除缓存
        String tokenKey = JwtConfig.TOKEN_PREFIX + oldName;
        if (redisTemplate.hasKey(tokenKey)) {
            redisTemplate.delete(tokenKey);
        }
        //更新配置文件
        insertOrUpdateAuthConfig(idAccount, dto);
    }

    private void addAccount(AccountDto dto) {
        LambdaQueryWrapper<Account> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Account::getName, dto.getName()).eq(Account::getIsDeleted, Boolean.FALSE);
        Account account = accountMapper.selectOne(wrapper);
        if (Preconditions.isNotBlank(account)) {
            throw new BusinessException(String.format("账号名【%s】已存在", dto.getName()));
        }
        account = BeanUtil.copyProperties(dto, Account.class);
        account.setPassword(PasswordUtils.passwd(dto.getPassword()));
        account.setAccountType(AccountTypeEnum.AUTH.getCode());
        account.setCreateTime(new Date());
        account.setUpdateTime(new Date());
        account.setIsDeleted(Boolean.FALSE);
        accountMapper.insert(account);
        //插入或更新授权配置
        insertOrUpdateAuthConfig(account, dto);
    }

    private void insertOrUpdateAuthConfig(Account account, AccountDto dto) {
        LambdaQueryWrapper<AccountAuthConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AccountAuthConfig::getAccountId, account.getId()).eq(AccountAuthConfig::getIsDeleted, Boolean.FALSE);
        AccountAuthConfig config = accountAuthConfigMapper.selectOne(wrapper);
        if (Preconditions.isBlank(config)) {
            config = new AccountAuthConfig();
        }
        BeanUtil.copyProperties(dto, config, "id");
        if (Preconditions.isBlank(config.getId())) {
            config.setAccountId(account.getId());
            config.setCreateTime(new Date());
            config.setUpdateTime(new Date());
            config.setIsDeleted(Boolean.FALSE);
            accountAuthConfigMapper.insert(config);
            return;
        }
        config.setUpdateTime(new Date());
        accountAuthConfigMapper.updateById(config);
    }

    @Override
    public RestResult<Boolean> del(Long accountId) {
        LambdaQueryWrapper<Account> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Account::getId, accountId).eq(Account::getIsDeleted, Boolean.FALSE);
        Account account = accountMapper.selectOne(wrapper);
        if (Preconditions.isBlank(account)) {
            throw new BusinessException(String.format("账号【%s】不存在", accountId));
        }
        LambdaQueryWrapper<AccountAuthConfig> cwrapper = new LambdaQueryWrapper<>();
        cwrapper.eq(AccountAuthConfig::getAccountId, account.getId()).eq(AccountAuthConfig::getIsDeleted, Boolean.FALSE);
        accountAuthConfigMapper.delete(cwrapper);
        return RestResult.ok(true);
    }

    @Override
    public RestResult<IPage<AccountVo>> page(AccountSearch dto) {
        LambdaQueryWrapper<Account> wrapper = getAccountWrapper(dto);
        Page<Account> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        IPage<Account> iPage = accountMapper.selectPage(page, wrapper);
        List<AccountAuthConfig> configs = getAccountAuthConfigs(iPage);
        Map<Long, AccountAuthConfig> configMap = null;
        Map<Long, Purchaser> purchaserMap = null;
        if (Preconditions.isNotBlank(configs)) {
            configMap = configs.stream().collect(Collectors.toMap(AccountAuthConfig::getAccountId, Function.identity()));
            List<Long> purchaserIds = configs.stream().map(AccountAuthConfig::getPurchaserId).collect(Collectors.toList());
            List<Purchaser> list = purchaserMapper.selectBatchIds(purchaserIds);
            purchaserMap = list.stream().collect(Collectors.toMap(Purchaser::getId, Function.identity()));
        }
        Map<Long, AccountAuthConfig> finalConfigMap = configMap;
        Map<Long, Purchaser> finalPurchaserMap = purchaserMap;
        IPage<AccountVo> convert = iPage.convert(t -> {
            AccountVo item = BeanUtil.copyProperties(t, AccountVo.class);
            item.setHhAromeSwitch(Boolean.FALSE);
            if (Preconditions.isNotBlank(finalConfigMap) && finalConfigMap.containsKey(t.getId())) {
                AccountAuthConfig config = finalConfigMap.get(t.getId());
                BeanUtil.copyProperties(config, item, "id");
                item.setPurchaserId(config.getPurchaserId());
                item.setHhAromeSwitch(config.getHhAromeSwitch());
                if (Preconditions.isNotBlank(finalPurchaserMap) && finalPurchaserMap.containsKey(config.getPurchaserId())) {
                    item.setPurchaserName(finalPurchaserMap.get(config.getPurchaserId()).getCompanyName());
                }
            }
            return item;
        });
        return RestResult.ok(convert);
    }

    @Override
    public RestResult<AccountVo> query(Account account) {
        return RestResult.ok(complete(account));
    }

    @Override
    public RestResult<List<AccountVo>> list() {
        LambdaQueryWrapper<Account> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Account::getId, Account::getName).eq(Account::getIsDeleted, Boolean.FALSE);
        List<Account> accounts = accountMapper.selectList(wrapper);
        List<AccountVo> vos = BeanUtil.copyToList(accounts, AccountVo.class);
        return RestResult.ok(vos != null ? vos : Collections.emptyList());
    }

    private AccountVo complete(Account account) {
        LambdaQueryWrapper<AccountAuthConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AccountAuthConfig::getAccountId, account.getId()).eq(AccountAuthConfig::getIsDeleted, Boolean.FALSE);
        AccountAuthConfig config = accountAuthConfigMapper.selectOne(wrapper);
        AccountVo accountVo = BeanUtil.copyProperties(account, AccountVo.class);
        if (Preconditions.isNotBlank(config)) {
            BeanUtil.copyProperties(config, accountVo, "id");
        }
        return accountVo;
    }

    private List<AccountAuthConfig> getAccountAuthConfigs(IPage<Account> iPage) {
        List<Account> records = iPage.getRecords();
        if (Preconditions.isBlank(records)) {
            return null;
        }
        List<Long> accountIds = records.stream().map(Account::getId).collect(Collectors.toList());
        LambdaQueryWrapper<AccountAuthConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(AccountAuthConfig::getAccountId, accountIds).eq(AccountAuthConfig::getIsDeleted, Boolean.FALSE);
        List<AccountAuthConfig> configs = accountAuthConfigMapper.selectList(wrapper);
        return configs;
    }

    private LambdaQueryWrapper<Account> getAccountWrapper(AccountSearch dto) {
        LambdaQueryWrapper<Account> wrapper = new LambdaQueryWrapper<>();
        List<Long> accountIds = new ArrayList<>();
        if (Preconditions.isNotBlank(dto.getAccountId())) {
            accountIds.add(dto.getAccountId());
        }
        handleAccountSearch(accountIds, dto);
        //查询的传参条件
        if (Preconditions.isNotBlank(accountIds)) {
            wrapper.in(Account::getId, accountIds);
        }
        //基础条件
        wrapper.ne(Account::getAccountType, AccountTypeEnum.ADMIN.getCode());
        wrapper.eq(Account::getIsDeleted, Boolean.FALSE);
        wrapper.orderByDesc(Account::getId);
        return wrapper;
    }

    private void handleAccountSearch(List<Long> accountIds, AccountSearch dto) {
        if (Preconditions.isBlank(dto.getHhAromeSwitch())
                && Preconditions.isBlank(dto.getPurchaserId())) {
            return;
        }
        LambdaQueryWrapper<AccountAuthConfig> cwrapper = new LambdaQueryWrapper<>();
        cwrapper.select(AccountAuthConfig::getId, AccountAuthConfig::getAccountId).eq(AccountAuthConfig::getIsDeleted, Boolean.FALSE);
        if (Preconditions.isNotBlank(dto.getHhAromeSwitch())) {
            cwrapper.eq(AccountAuthConfig::getHhAromeSwitch, dto.getHhAromeSwitch());
        }
        if (Preconditions.isNotBlank(dto.getPurchaserId())) {
            cwrapper.eq(AccountAuthConfig::getPurchaserId, dto.getPurchaserId());
        }
        List<AccountAuthConfig> configs = accountAuthConfigMapper.selectList(cwrapper);
        if (Preconditions.isBlank(configs)) {
            accountIds.add(-1L);
            return;
        }
        accountIds.addAll(configs.stream().map(AccountAuthConfig::getAccountId).distinct().collect(Collectors.toList()));
    }


}
