package com.cool.store.service.fees.impl;

import cn.hutool.core.collection.CollStreamUtil;
import com.cool.store.constants.RedisConstant;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dao.EnterpriseUserDAO;
import com.cool.store.dao.modify.ModifyRecordDAO;
import com.cool.store.dao.fees.WalletAllocationCompanyDAO;
import com.cool.store.dao.fees.WalletAllocationConfigDAO;
import com.cool.store.dto.wallet.CompanyListDTO;
import com.cool.store.entity.fees.WalletAllocationCompanyDO;
import com.cool.store.entity.fees.WalletAllocationConfigDO;
import com.cool.store.enums.BusinessModuleEnum;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.fees.WalletCompanyQueryRequest;
import com.cool.store.request.fees.WalletAllocationCompanyRequest;
import com.cool.store.request.fees.WalletAllocationConfigAddRequest;
import com.cool.store.request.fees.WalletAllocationConfigPageRequest;
import com.cool.store.request.wallet.*;
import com.cool.store.service.dict.impl.DictService;
import com.cool.store.service.fees.WalletAllocationConfigService;
import com.cool.store.service.wallet.WalletApiService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.vo.fees.InvestDivisionRegionVO;
import com.cool.store.vo.fees.WalletAllocationCompanyVO;
import com.cool.store.vo.fees.WalletAllocationConfigVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.cool.store.service.wallet.impl.WalletServiceImpl.toPageInfo;

/**
 * 分账配置服务实现类
 *
 * @author system
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WalletAllocationConfigServiceImpl implements WalletAllocationConfigService {

    private final WalletAllocationConfigDAO walletAllocationConfigDAO;
    private final WalletAllocationCompanyDAO walletAllocationCompanyDAO;
    private final ModifyRecordDAO modifyRecordDAO;
    private final RedisUtilPool redisUtilPool;
    private final DictService dictService;
    private final WalletApiService walletApiService;
    private final EnterpriseUserDAO enterpriseUserDAO;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(WalletAllocationConfigAddRequest request) {
        verify(request.getJoinBrand(), request.getExpenseType(), request.getInvestDivisionId(), request.getId());
        String userId = CurrentUserHolder.getUserId();

        WalletAllocationConfigDO configDO = BeanUtil.toBean(request, WalletAllocationConfigDO.class);
        configDO.setCreateUserId(userId);
        walletAllocationConfigDAO.insertSelective(configDO);

        // 保存分账公司配置
        insertCompanyList(request.getCompanyList(), configDO.getId(), userId);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(WalletAllocationConfigAddRequest request) {
        verify(request.getJoinBrand(), request.getExpenseType(), request.getInvestDivisionId(), request.getId());

        WalletAllocationConfigDO configDO = BeanUtil.toBean(request, WalletAllocationConfigDO.class);
        walletAllocationConfigDAO.updateByPrimaryKeySelective(configDO);

        String userId = CurrentUserHolder.getUserId();
        walletAllocationCompanyDAO.deleteByConfigId(request.getId());
        // 保存分账公司配置
        insertCompanyList(request.getCompanyList(), configDO.getId(), userId);

        // 新增业务修改记录
        modifyRecordDAO.insertRecord(BusinessModuleEnum.WALLET_ALLOCATION_CONFIG, request.getId(), userId);
        return true;
    }

    public void insertCompanyList(List<WalletAllocationCompanyRequest> companyList, Long configId, String userId) {
        if (CollectionUtils.isNotEmpty(companyList)) {
            List<WalletAllocationCompanyDO> list = BeanUtil.toList(companyList, WalletAllocationCompanyDO.class);
            list.forEach(v -> {
                v.setConfigId(configId);
                v.setCreateUserId(userId);
            });
            walletAllocationCompanyDAO.insertBatch(list);
        }
    }

    @Override
    public PageInfo<WalletAllocationConfigVO> page(WalletAllocationConfigPageRequest request) {
        List<Long> configIds = null;
        if (Objects.nonNull(request.getPayeeCode())) {
            List<WalletAllocationCompanyDO> companyList = walletAllocationCompanyDAO.selectByPayeeCode(request.getPayeeCode());
            if (CollectionUtils.isEmpty(companyList)) {
                return new PageInfo<>();
            }
            configIds = CollStreamUtil.toList(companyList, WalletAllocationCompanyDO::getConfigId);
        }
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        // 查询分账配置
        List<WalletAllocationConfigDO> configList = walletAllocationConfigDAO.selectByCondition(
                request.getJoinBrand(),
                request.getInvestDivisionId(),
                request.getExpenseType(),
                configIds
        );
        PageInfo<WalletAllocationConfigDO> page = new PageInfo<>(configList);
        PageInfo<WalletAllocationConfigVO> newPage = BeanUtil.toPage(page, WalletAllocationConfigVO.class);
        List<Long> resultConfigIds = CollStreamUtil.toList(configList, WalletAllocationConfigDO::getId);
        Set<String> userIds = CollStreamUtil.toSet(configList, WalletAllocationConfigDO::getCreateUserId);
        Map<Long, List<WalletAllocationCompanyDO>> companyGroup = walletAllocationCompanyDAO.selectGroupByConfigIds(resultConfigIds);
        Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(new ArrayList<>(userIds));

        newPage.getList().forEach(v -> {
            v.setInvestDivisionName(redisUtilPool.hashGet(RedisConstant.WALLET_ALLOCATION_CONFIG_INVEST_DIVISION, String.valueOf(v.getInvestDivisionId())));
            List<WalletAllocationCompanyDO> companyList = companyGroup.getOrDefault(v.getId(), Collections.emptyList());
            v.setCompanyList(BeanUtil.toList(companyList, WalletAllocationCompanyVO.class));
            v.setCreateUserName(userNameMap.get(v.getCreateUserId()));
        });
        dictService.fillDictField(newPage.getList());
        return newPage;
    }

    @Override
    public List<InvestDivisionRegionVO> getInvestDivisionRegionList() {
        Map<String, String> map = redisUtilPool.hashGetAll(RedisConstant.WALLET_ALLOCATION_CONFIG_INVEST_DIVISION);
        return map.entrySet().stream()
                .map(v -> new InvestDivisionRegionVO(Long.valueOf(v.getKey()), v.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public PageInfo<WalletAllocationCompanyVO> companyPage(WalletCompanyQueryRequest request) {
        FindPageCompanyRequest apiRequest = new FindPageCompanyRequest();
        apiRequest.setCompanyName(request.getCompanyName());
        apiRequest.setCompanyCode(request.getCompanyCode());
        apiRequest.setPage(new WalletBasicPageInfo(request.getPageNum(), request.getPageSize()));
        CompanyListDTO companyInfo = walletApiService.getCompanyInfo(apiRequest);
        List<WalletAllocationCompanyVO> list = CollStreamUtil.toList(companyInfo.getPageData(), v -> new WalletAllocationCompanyVO(v.getCompanyName(), v.getCompanyCode()));
        return toPageInfo(list, WalletAllocationCompanyVO.class, companyInfo.getPage());
    }

    /**
     * 校验同种费用只允许配置分部或者全部，存在另一种时报错
     */
    private void verify(Integer joinBrand, String expenseType, Long investDivisionId, Long excludeId) {
        if (walletAllocationConfigDAO.existOtherInvestType(joinBrand, expenseType, investDivisionId, excludeId)) {
            throw new ServiceException(ErrorCodeEnum.WALLET_INVEST_TYPE_EXISTS);
        }
        if (walletAllocationConfigDAO.existUniqueKey(joinBrand, investDivisionId, expenseType, excludeId)) {
            throw new ServiceException(ErrorCodeEnum.WALLET_UNIQUE_KEY_EXISTS);
        }
    }
}

