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

import cn.hutool.core.collection.CollStreamUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.RedisConstant;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dao.EnterpriseUserDAO;
import com.cool.store.dao.FranchiseFeeDAO;
import com.cool.store.dao.RegionDao;
import com.cool.store.dao.ShopInfoDAO;
import com.cool.store.dao.modify.ModifyRecordDAO;
import com.cool.store.dao.fees.PayeeBankConfigDAO;
import com.cool.store.entity.FranchiseFeeDO;
import com.cool.store.entity.RegionDO;
import com.cool.store.entity.ShopInfoDO;
import com.cool.store.entity.fees.PayeeBankConfigDO;
import com.cool.store.enums.BusinessModuleEnum;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.fees.PayeeBankConfigAddRequest;
import com.cool.store.request.fees.PayeeBankConfigPageRequest;
import com.cool.store.service.fees.PayeeBankConfigService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.utils.poi.StringUtils;
import com.cool.store.vo.fees.PayeeBankConfigVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 线下收款银行配置Service实现
 */
@Service
@RequiredArgsConstructor
public class PayeeBankConfigServiceImpl implements PayeeBankConfigService {

    private final PayeeBankConfigDAO payeeBankConfigDAO;
    private final RedisUtilPool redisUtilPool;
    private final ModifyRecordDAO modifyRecordDAO;
    private final EnterpriseUserDAO enterpriseUserDAO;
    private final ShopInfoDAO shopInfoDAO;
    private final FranchiseFeeDAO franchiseFeeDAO;
    private final RegionDao regionDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(PayeeBankConfigAddRequest request) {
        verify(request.getJoinBrand(), request.getInvestDivisionId(), request.getPayType(), null);

        String userId = CurrentUserHolder.getUserId();
        PayeeBankConfigDO configDO = BeanUtil.toBean(request, PayeeBankConfigDO.class);
        configDO.setCreateUserId(userId);
        payeeBankConfigDAO.insertSelective(configDO);
        return true;
    }

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

        PayeeBankConfigDO updateDO = BeanUtil.toBean(request, PayeeBankConfigDO.class);
        payeeBankConfigDAO.updateByPrimaryKeySelective(updateDO);

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

    @Override
    public PageInfo<PayeeBankConfigVO> page(PayeeBankConfigPageRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<PayeeBankConfigDO> list = payeeBankConfigDAO.selectByCondition(
                request.getJoinBrand(),
                request.getInvestDivisionId(),
                request.getPayType()
        );
        PageInfo<PayeeBankConfigDO> page = new PageInfo<>(list);
        PageInfo<PayeeBankConfigVO> newPage = BeanUtil.toPage(page, PayeeBankConfigVO.class);
        Set<String> userIds = CollStreamUtil.toSet(list, PayeeBankConfigDO::getCreateUserId);
        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())));
            v.setCreateUserName(userNameMap.get(v.getCreateUserId()));
        });
        return newPage;
    }

    @Override
    public PayeeBankConfigVO getByShopId(Long shopId, Integer payType) {
        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(shopId);
        if (Objects.isNull(shopInfo)) {
            throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
        }
        FranchiseFeeDO franchiseFeeDO = franchiseFeeDAO.selectByShopId(shopId);
        if (Objects.isNull(payType) && (Objects.isNull(franchiseFeeDO) || Objects.isNull(franchiseFeeDO.getPayType()))) {
            return getDefaultBankConfig(shopInfo.getFranchiseBrand());
        }
        RegionDO regionDO = regionDao.getRegionById(shopInfo.getInvestRegionId());
        if (Objects.isNull(regionDO)) {
            return getDefaultBankConfig(shopInfo.getFranchiseBrand());
        }
        PayeeBankConfigDO configDO = payeeBankConfigDAO.getByUniqueKey(Integer.valueOf(shopInfo.getFranchiseBrand()), Long.valueOf(regionDO.getParentId()), Objects.nonNull(payType) ? payType : franchiseFeeDO.getPayType());
        return BeanUtil.toBean(configDO, PayeeBankConfigVO.class);
    }

    public PayeeBankConfigVO getDefaultBankConfig(String franchiseBrand) {
        String bankInfoStr = redisUtilPool.hashGet(RedisConstant.PAYEE_BANK_CONFIG_DEFAULT, franchiseBrand);
        if (StringUtils.isBlank(bankInfoStr)) {
            bankInfoStr = redisUtilPool.hashGet(RedisConstant.PAYEE_BANK_CONFIG_DEFAULT, "1");
        }
        if (StringUtils.isNotBlank(bankInfoStr)) {
            JSONObject bankInfo = JSONObject.parseObject(bankInfoStr);
            return PayeeBankConfigVO.builder()
                    .payeeName(bankInfo.getString("payeeName"))
                    .payeeAccount(bankInfo.getString("payeeAccount"))
                    .payeeBank(bankInfo.getString("payeeBank"))
                    .payeeBankBranch(bankInfo.getString("payeeBankBranch"))
                    .build();
        }
        return null;
    }

    /**
     * 校验：
     * 1) 加盟品牌+招商分部+付款方式唯一
     * 2) 同品牌同支付方式只能存在分部或全部
     */
    private void verify(Integer joinBrand, Long investDivisionId, Integer payType, Long excludeId) {
        if (payeeBankConfigDAO.existOtherInvestType(joinBrand, payType, investDivisionId, excludeId)) {
            throw new ServiceException(ErrorCodeEnum.BANK_CONFIG_INVEST_TYPE_EXISTS);
        }
        if (payeeBankConfigDAO.existUniqueKey(joinBrand, investDivisionId, payType, excludeId)) {
            throw new ServiceException(ErrorCodeEnum.BANK_CONFIG_UNIQUE_KEY_EXISTS);
        }
    }
}


