package com.cool.store.service.close.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.*;
import com.cool.store.dto.close.CloseStoreMkUserDTO;
import com.cool.store.dto.wallet.BankListDTO;
import com.cool.store.dto.xgj.XgjBranchBankDTO;
import com.cool.store.dto.xgj.XgjPartnerPageDTO;
import com.cool.store.dto.xgj.XgjPayResultDTO;
import com.cool.store.entity.CloseStoreInfoDO;
import com.cool.store.entity.CloseStoreRefundInfoDO;
import com.cool.store.entity.EnterpriseUserDO;
import com.cool.store.entity.StoreDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.close.CloseStoreSubStageEnum;
import com.cool.store.enums.close.CloseStoreSubStageStatusEnum;
import com.cool.store.enums.close.RefundPayStatusEnum;
import com.cool.store.enums.close.XgjRefundPayStatusEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.close.refund.CloseStoreRefundAddRequest;
import com.cool.store.request.close.refund.CloseStoreRefundQueryRequest;
import com.cool.store.request.close.refund.CloseStoreRefundSkipRequest;
import com.cool.store.request.close.refund.CloseStoreRefundUpdateRequest;
import com.cool.store.request.close.refund.*;
import com.cool.store.request.wallet.GetBankRequest;
import com.cool.store.request.wallet.WalletBasicPageInfo;
import com.cool.store.request.xgj.*;
import com.cool.store.service.ThirdXgjService;
import com.cool.store.service.close.CloseStoreRefundService;
import com.cool.store.service.close.CloseStoreService;
import com.cool.store.service.dict.impl.DictService;
import com.cool.store.service.wallet.WalletApiService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.CommonContextUtil;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.vo.close.refund.CloseStoreRefundDetailVO;
import com.cool.store.vo.close.refund.CloseStoreRefundListVO;
import com.cool.store.vo.close.refund.CloseStoreRefundSimpleVO;
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.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>
 * 闭店退款 服务实现类
 * </p>
 *
 * @author wangff
 * @since 2025/10/13
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CloseStoreRefundServiceImpl implements CloseStoreRefundService {
    private final CloseStoreRefundInfoDAO closeStoreRefundInfoDAO;
    private final CloseStoreInfoDAO closeStoreInfoDAO;
    private final CloseStoreStageInfoDAO closeStoreStageInfoDAO;
    private final CloseStoreService closeStoreService;
    private final StoreDao storeDao;
    private final RedisUtilPool redisUtilPool;
    private final ThirdXgjService thirdXgjService;
    private final EnterpriseUserDAO enterpriseUserDAO;
    private final DictService dictService;
    private final WalletApiService walletApiService;

    @Override
    public Boolean addRefund(CloseStoreRefundAddRequest request) {
        if (!CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.getCloseStoreSubStage().equals(request.getType())
                && !CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_40.getCloseStoreSubStage().equals(request.getType())) {
            throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_TYPE_ERROR);
        }
        CloseStoreMkUserDTO mkUser = getCurrentMkUser();
        // 校验是否有每刻权限
        if (Objects.isNull(mkUser)) {
            throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_MK_USER_NOT_EXIST);
        }
        // 是否存在非作废状态的记录，则不能新增
        if (closeStoreRefundInfoDAO.existEffectiveRecord(request.getCloseStoreId(), request.getType())) {
            throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_EXIST_EFFECTIVE_RECORD);
        }
        CloseStoreInfoDO closeStoreInfo = closeStoreInfoDAO.getById(request.getCloseStoreId());
        if (Objects.isNull(closeStoreInfo)) {
            throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
        }
        StoreDO storeDO = storeDao.getByStoreId(closeStoreInfo.getStoreId());
        if (Objects.isNull(storeDO)) {
            throw new ServiceException(ErrorCodeEnum.STORE_NOT_FIND);
        }

        CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(request.getType());
        CloseStoreSubStageStatusEnum expectedStageStatus = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.equals(subStage) ? CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_35 : CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_45;
        assert subStage != null;
        // 校验阶段状态
        closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), subStage.getCloseStoreStageEnum(), subStage, expectedStageStatus);

        CloseStoreRefundInfoDO refundInfoDO = BeanUtil.toBean(request, CloseStoreRefundInfoDO.class);
        refundInfoDO.setRefundNo(generateCloseStoreNo());
        // 提交新管家
        dictService.fillDictField(request);
        XgjReimburseRequest xgjReimburseRequest = request.convertToXgjRequest(mkUser, closeStoreInfo.getCloseReason(), storeDO);
        String orderNo = thirdXgjService.reimburse(xgjReimburseRequest);
        refundInfoDO.setRefundOrderNo(orderNo);
        refundInfoDO.setRefundStatus(RefundPayStatusEnum.APPROVING.getStatus());
        refundInfoDO.setSubmitterId(StringUtils.isNotBlank(refundInfoDO.getSubmitterId()) ? refundInfoDO.getSubmitterId() : mkUser.getJobnumber());
        refundInfoDO.setSubmitterName(StringUtils.isNotBlank(refundInfoDO.getSubmitterName()) ? refundInfoDO.getSubmitterName() : mkUser.getName());
        return closeStoreRefundInfoDAO.insertSelective(refundInfoDO);
    }

    @Override
    public Boolean updateRefund(CloseStoreRefundUpdateRequest request) {
        CloseStoreMkUserDTO mkUser = getCurrentMkUser();
        // 校验是否有每刻权限
        if (Objects.isNull(mkUser)) {
            throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_MK_USER_NOT_EXIST);
        }
        CloseStoreRefundInfoDO old = closeStoreRefundInfoDAO.getById(request.getId());
        if (Objects.isNull(old)) {
            throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_INFO_NOT_EXIST);
        }
        CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(old.getType());
        CloseStoreSubStageStatusEnum expectedStageStatus = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.equals(subStage) ? CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_35 : CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_45;
        assert subStage != null;
        // 校验阶段状态
        closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), subStage.getCloseStoreStageEnum(), subStage, expectedStageStatus);

        CloseStoreRefundInfoDO refundInfoDO = BeanUtil.toBean(request, CloseStoreRefundInfoDO.class);
        refundInfoDO.setSubmitterId(StringUtils.isNotBlank(refundInfoDO.getSubmitterId()) ? refundInfoDO.getSubmitterId() : mkUser.getJobnumber());
        refundInfoDO.setSubmitterName(StringUtils.isNotBlank(refundInfoDO.getSubmitterName()) ? refundInfoDO.getSubmitterName() : mkUser.getName());
        return closeStoreRefundInfoDAO.updateSelective(refundInfoDO);
    }

    @Override
    public CloseStoreMkUserDTO getCurrentMkUser() {
        EnterpriseUserDO user = enterpriseUserDAO.getUserInfoById(CurrentUserHolder.getUserId());
        if (StringUtils.isBlank(user.getJobnumber())) {
            return null;
        }
        String mkUserStr = redisUtilPool.hashGet(RedisConstant.MK_USER_MAPPING, user.getJobnumber());
        if (StringUtils.isNotBlank(mkUserStr)) {
            return JSONObject.parseObject(mkUserStr, CloseStoreMkUserDTO.class);
        }
        return null;
    }

    @Override
    public CloseStoreRefundDetailVO getRefundDetail(Long id) {
        CloseStoreRefundInfoDO refundInfoDO = closeStoreRefundInfoDAO.getById(id);
        if (Objects.nonNull(refundInfoDO)) {
            CloseStoreRefundDetailVO vo = BeanUtil.toBean(refundInfoDO, CloseStoreRefundDetailVO.class);
            CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(refundInfoDO.getCloseStoreId());
            if (Objects.nonNull(closeStoreInfoDO)) {
                vo.setCloseReason(closeStoreInfoDO.getCloseReason());
            }
            dictService.fillDictField(vo);
            return vo;
        }
        return null;
    }

    @Override
    @Transactional
    public void completeRefund(Long refundId, Date refundTime) {
        CloseStoreRefundInfoDO refundInfoDO = closeStoreRefundInfoDAO.getById(refundId);
        if (Objects.nonNull(refundInfoDO) && !RefundPayStatusEnum.PAY_SUCCESS.getStatus().equals(refundInfoDO.getRefundStatus())) {
            CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(refundInfoDO.getType());
            if (Objects.nonNull(subStage)) {
                // 修改退款状态
                closeStoreRefundInfoDAO.updateRefundStatus(refundId, RefundPayStatusEnum.PAY_SUCCESS.getStatus(), refundTime);
                // 流程流转
                closeStoreService.closeStoreProcessFlow(refundInfoDO.getCloseStoreId(), subStage);
            }
        }
    }

    @Override
    public PageInfo<CloseStoreRefundSimpleVO> getRefundSimpleList(CloseStoreRefundQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<CloseStoreRefundInfoDO> list = closeStoreRefundInfoDAO.getListByCloseStoreId(request.getCloseStoreId(), request.getType());
        PageInfo<CloseStoreRefundInfoDO> page = new PageInfo<>(list);
        return BeanUtil.toPage(page, CloseStoreRefundSimpleVO.class);
    }

    @Override
    @Transactional
    public void skip(CloseStoreRefundSkipRequest request) {
        CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(request.getType());
        CloseStoreSubStageStatusEnum expectedStageStatus = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.equals(subStage) ? CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_35 : CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_45;
        assert subStage != null;
        closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), subStage.getCloseStoreStageEnum(), subStage, expectedStageStatus);
        // 流程流转
        closeStoreService.closeStoreProcessFlow(request.getCloseStoreId(), subStage);
    }

    @Override
    public PageInfo<CloseStoreRefundListVO> refundPage(CloseStoreRefundQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<CloseStoreRefundInfoDO> list = closeStoreRefundInfoDAO.getListByCloseStoreId(request.getCloseStoreId(), request.getType());
        PageInfo<CloseStoreRefundInfoDO> page = new PageInfo<>(list);
        return BeanUtil.toPage(page, CloseStoreRefundListVO.class);
    }

    @Override
    @Transactional
    public Boolean refreshRefundOrderStatus(CloseStoreRefundQueryRequest request) {
        List<CloseStoreRefundInfoDO> list = closeStoreRefundInfoDAO.getListByCloseStoreId(request.getCloseStoreId(), request.getType());
        List<CloseStoreRefundInfoDO> updateList = new ArrayList<>();
        List<CloseStoreRefundInfoDO> completeList = new ArrayList<>();
        refreshRefund(list, updateList, completeList);
        if (CollectionUtils.isNotEmpty(updateList)) {
            closeStoreRefundInfoDAO.updateRefundStatusBatchById(updateList);
        }
        if (CollectionUtils.isNotEmpty(completeList)) {
            for (CloseStoreRefundInfoDO refundInfoDO : completeList) {
                completeRefund(refundInfoDO.getId(), refundInfoDO.getRefundTime());
            }
        }
        return true;
    }

    @Override
    public void refreshRefund(List<CloseStoreRefundInfoDO> list, List<CloseStoreRefundInfoDO> updateList, List<CloseStoreRefundInfoDO> completeList) {
        for (CloseStoreRefundInfoDO refundInfoDO : list) {
            try {
                if (com.cool.store.utils.poi.StringUtils.isNotBlank(refundInfoDO.getRefundOrderNo())) {
                    XgjPayResultDTO xgjPayResultDTO = thirdXgjService.queryOrderStatus(new XgjPaymentRequest(refundInfoDO.getRefundOrderNo()));
                    String xgjStatus = xgjPayResultDTO.getStatus();
                    String refundStatus = XgjRefundPayStatusEnum.REJECTED.getStatus().equals(xgjStatus) ? RefundPayStatusEnum.APPROVING.getStatus() : xgjStatus;
                    if (!refundInfoDO.getRefundStatus().equals(refundStatus)) {
                        CloseStoreRefundInfoDO update = CloseStoreRefundInfoDO.builder()
                                .id(refundInfoDO.getId())
                                .refundStatus(refundStatus)
                                .refundTime(CoolDateUtils.parseDate(xgjPayResultDTO.getPaySuccessTime(), "yyyy-MM-dd HH:mm:ss"))
                                .build();
                        if (refundStatus.equals(RefundPayStatusEnum.PAY_SUCCESS.getStatus())) {
                            completeList.add(update);
                        } else {
                            updateList.add(update);
                        }
                    }
                }
            } catch (Exception e) {
                log.info("退款状态查询失败, refundId:{}", refundInfoDO.getId());
                log.info("退款状态查询失败", e);
            }
        }
    }

    @Override
    public Boolean savePartner(CloseStorePartnerRequest request) {
        XgjSavePartnerRequest xgjSavePartnerRequest = request.convertXgj();
        thirdXgjService.savePartner(xgjSavePartnerRequest);
        return true;
    }

    @Override
    public XgjPartnerPageDTO queryPartnerPage(CloseStorePartnerQueryRequest request) {
        XgjPartnerQueryRequest xgjPartnerQueryRequest = request.convertXgj();
        return thirdXgjService.queryPartnerPage(xgjPartnerQueryRequest);
    }

    @Override
    public List<XgjBranchBankDTO> queryBranchBankList(XgjBankQueryRequest request) {
        String profileName = CommonContextUtil.getProfileName();
        if (Arrays.asList("test", "ab", "local").contains(profileName)) {
            GetBankRequest bankRequest = new GetBankRequest();
            bankRequest.setPage(new WalletBasicPageInfo(1, 5));
            bankRequest.setKeyword(request.getOpenBankName());
            BankListDTO bankList = walletApiService.getBankList(bankRequest);
            return CollStreamUtil.toList(bankList.getPageData(), v -> new XgjBranchBankDTO(v.getBranchName(), v.getBranchCode()));
        } else {
            return thirdXgjService.queryBranchBankList(request);
        }
    }

    /**
     * 生成退款申请单号
     */
    private String generateCloseStoreNo(){
        return "T" + CoolDateUtils.getTodayMillis();
    }
}
