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

import cn.hutool.core.collection.CollStreamUtil;
import com.cool.store.constants.DictConstants;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dao.RegionDao;
import com.cool.store.dao.ShopInfoDAO;
import com.cool.store.dao.dict.SysDictColumnDAO;
import com.cool.store.dao.fees.*;
import com.cool.store.entity.RegionDO;
import com.cool.store.entity.ShopInfoDO;
import com.cool.store.entity.fees.*;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.fees.AllocationPayStatusEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.fees.ShopAllocationInfoRequest;
import com.cool.store.service.dict.impl.DictService;
import com.cool.store.service.fees.ShopAllocationInfoService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.vo.dict.DictColumnSimpleVO;
import com.cool.store.vo.fees.ShopAllocationSimpleVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 门店平安钱包分账信息服务实现类
 * </p>
 *
 * @author wangff
 * @since 2026/1/29
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ShopAllocationInfoServiceImpl implements ShopAllocationInfoService {
    private final ShopAllocationInfoDAO shopAllocationInfoDAO;
    private final SysDictColumnDAO dictColumnDAO;
    private final WalletAllocationConfigDAO walletAllocationConfigDAO;
    private final WalletAllocationCompanyDAO walletAllocationCompanyDAO;
    private final FeeStandardConfigDAO feeStandardConfigDAO;
    private final ShopInfoDAO shopInfoDAO;
    private final RegionDao regionDao;
    private final WalletPayInfoDAO walletPayInfoDAO;
    private final DictService dictService;

    @Override
    public List<ShopAllocationInfoDO> getOrDefault(Long shopId) {
        List<ShopAllocationInfoDO> list = shopAllocationInfoDAO.getByShopId(shopId);
        if (CollectionUtils.isEmpty(list)) {
            list = getDefault(shopId);
        }
        return list;
    }

    @Override
    public List<ShopAllocationSimpleVO> getSimpleInfo(Long shopId) {
        List<ShopAllocationInfoDO> list = shopAllocationInfoDAO.getByShopId(shopId);
        List<ShopAllocationSimpleVO> result = BeanUtil.toList(list, ShopAllocationSimpleVO.class);
        dictService.fillDictField(result);
        result.forEach(v -> v.setGroupName(v.getExpenseType()));
        return result;
    }

    @Override
    public void insertBatch(Long shopId, List<ShopAllocationInfoRequest> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<ShopAllocationInfoDO> infoList = BeanUtil.toList(list, ShopAllocationInfoDO.class);
        String userId = CurrentUserHolder.getUserId();
        infoList.forEach(v -> {
            v.setShopId(shopId);
            v.setCreateUserId(userId);
            v.setUpdateUserId(userId);
            v.setStatus(AllocationPayStatusEnum.UNPAID.getStatus());
        });
        shopAllocationInfoDAO.insertOrUpdateBatch(infoList);
    }

    @Override
    public void updateBatch(Long shopId, List<ShopAllocationInfoRequest> list) {
        // 存在缴费信息则无法更改
        if (walletPayInfoDAO.existPayInfo(shopId)) {
            throw new ServiceException(ErrorCodeEnum.EXIST_PAY_INFO);
        }
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<ShopAllocationInfoDO> infoList = BeanUtil.toList(list, ShopAllocationInfoDO.class);
        String userId = CurrentUserHolder.getUserId();
        infoList.forEach(v -> {
            v.setShopId(shopId);
            v.setUpdateUserId(userId);
        });
        shopAllocationInfoDAO.insertOrUpdateBatch(infoList);
    }

    /**
     * 获取默认配置
     * @param shopId 门店id
     * @return 分账信息列表
     */
    public List<ShopAllocationInfoDO> getDefault(Long shopId) {
        List<DictColumnSimpleVO> expenseTypes = dictColumnDAO.getOpenColumnListByTableCode(Collections.singletonList(DictConstants.EXPENSE_TYPE));
        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(shopId);
        if (Objects.isNull(shopInfo)) {
            throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
        }
        RegionDO regionDO = regionDao.getRegionById(shopInfo.getInvestRegionId());
        if (Objects.isNull(regionDO)) {
            log.error("未分配招商区域");
            return Collections.emptyList();
        }
        Integer joinBrand = Integer.valueOf(shopInfo.getFranchiseBrand());
        // 查询分账公司配置
        List<WalletAllocationConfigDO> allocationConfigList = walletAllocationConfigDAO.selectByBrandAndInvest(joinBrand, Long.valueOf(regionDO.getParentId()));
        List<Long> allocationConfigIds = CollStreamUtil.toList(allocationConfigList, WalletAllocationConfigDO::getId);
        Map<Long, List<WalletAllocationCompanyDO>> allocationCompanyMap = walletAllocationCompanyDAO.selectGroupByConfigIds(allocationConfigIds);
        Map<String, WalletAllocationCompanyDO> allocationCompanyConfig = CollStreamUtil.toMap(allocationConfigList, WalletAllocationConfigDO::getExpenseType, v -> allocationCompanyMap.getOrDefault(v.getId(), Collections.emptyList())
                .stream()
                .findFirst()
                .orElse(null)
        );
        // 查询加盟费用标准收费额配置
        Map<String, FeeStandardConfigDO> standardConfigMap = feeStandardConfigDAO.getStandardConfigMap(joinBrand);
        // 查询配置
        return expenseTypes.stream()
                .filter(v -> DictConstants.PING_AN_DEFAULT_ALLOCATION_EXPENSE_TYPE_CODES.contains(v.getColumnCode()))
                .map(v -> {
                    FeeStandardConfigDO standardConfigDO = standardConfigMap.get(v.getColumnCode());
                    WalletAllocationCompanyDO allocationCompanyDO = allocationCompanyConfig.get(v.getColumnCode());
                    return ShopAllocationInfoDO.builder()
                            .shopId(shopId)
                            .expenseType(v.getColumnCode())
                            .payeeName(Objects.nonNull(allocationCompanyDO) ? allocationCompanyDO.getPayeeName() : null)
                            .payeeCode(Objects.nonNull(allocationCompanyDO) ? allocationCompanyDO.getPayeeCode() : null)
                            .amount(Objects.nonNull(standardConfigDO) ? standardConfigDO.getAmount() : BigDecimal.ZERO)
                            .status(AllocationPayStatusEnum.UNPAID.getStatus())
                            .build();
                })
                .collect(Collectors.toList());
    }
}
