package com.yc.ship.module.trade.service.order.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdcardUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.mybatis.core.util.MyBatisUtils;
import com.yc.ship.framework.security.core.util.SecurityFrameworkUtils;
import com.yc.ship.module.resource.ResourceApi;
import com.yc.ship.module.resource.api.dto.CheckMachineDTO;
import com.yc.ship.module.system.api.user.AdminUserApi;
import com.yc.ship.module.system.api.user.dto.AdminUserRespDTO;
import com.yc.ship.module.trade.controller.admin.order.vo.check.*;
import com.yc.ship.module.trade.controller.app.pda.vo.PdaCheckStaticReqVO;
import com.yc.ship.module.trade.controller.app.pda.vo.PdaCheckStaticRespVO;
import com.yc.ship.module.trade.controller.app.pda.vo.PdaCheckTotalStaticRespVO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeDetailDO;
import com.yc.ship.module.trade.dal.mysql.order.TradeCheckMapper;
import com.yc.ship.module.trade.dal.mysql.order.TradeDetailMapper;
import com.yc.ship.module.trade.enums.CheckCodeTypeEnum;
import com.yc.ship.module.trade.enums.CheckMachineTypeEnum;
import com.yc.ship.module.trade.enums.CheckTypeEnum;
import com.yc.ship.module.trade.framework.common.IPUtils;
import com.yc.ship.module.trade.service.order.TradeCheckHandleService;
import com.yc.ship.module.trade.service.order.TradeCheckService;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.framework.common.pojo.CommonResult.error;
import static com.yc.ship.framework.common.pojo.CommonResult.success;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.*;

/**
 * 订单核销服务
 *
 * @author JuneQI
 * &#064;date  2025/8/16 17:39
 */
@Slf4j
@Service
@Validated
@RequiredArgsConstructor
public class TradeCheckServiceImpl implements TradeCheckService {
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private ResourceApi resourceApi;
    @Resource
    private TradeDetailMapper tradeDetailMapper;
    @Resource
    private TradeCheckMapper tradeCheckMapper;
    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;
    @Resource
    private TradeCheckHandleService tradeCheckHandleService;

    @Override
    public CommonResult<List<TradeCheckRespVO>> checkCommon(TradeCheckReqVO checkReqVO) {

        if (CheckTypeEnum.needOperatorId(checkReqVO.getType())) {
            Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
            if (!Objects.isNull(checkReqVO.getOperatorId())) {
                loginUserId = Long.parseLong(checkReqVO.getOperatorId());
            }
            AdminUserRespDTO userResult = adminUserApi.getUser(loginUserId);
            Assert.isFalse(Objects.isNull(userResult), () -> exception(OPERATOR_NOT_EXIST));
            checkReqVO.setOperatorId(userResult.getId().toString());
            checkReqVO.setOperatorName(userResult.getNickname());
        }
        List<TradeCheckRespVO> result = new ArrayList<>();
        try {
            String[] checkCodes = checkReqVO.getCheckCodes().split(",");
            for (String checkCode : checkCodes) {
                List<TradeCheckRespVO> list = new ArrayList<>();
                switch (checkReqVO.getCodeType()) {
                    case 0:
                        result.add(tradeCheckHandleService.checkVoucherHandle(checkCode, checkReqVO, null));
                        break;
                    case 1:
                        list = tradeCheckHandleService.checkOrderHandle(checkCode, checkReqVO);
                        break;
                    case 2:
                        list = tradeCheckHandleService.checkCardNoHandle(checkCode, checkReqVO);
                        break;
                    case 3:
                        break;
                    case 4:
                        result.add(tradeCheckHandleService.checkOtherHandle(checkCode, checkReqVO));
                        break;
                }
                result.addAll(list);
            }
        } catch (Exception e) {
            log.error("小程序方式核销失败: {},{}", checkReqVO.hashCode(), e.getMessage());
        }
        return success(result);
    }

    @Override
    public CommonResult<List<TradeCheckRespVO>> checkGate(TradeCheckReqVO checkReqVO) {
        Assert.isFalse(Objects.isNull(checkReqVO.getMachineId()), () -> exception(MACHINE_ID_NOT_EXIST));
        log.debug("开始检票：" + checkReqVO.getMachineId() + ";checkCodes=" + checkReqVO.getCheckCodes());
        CommonResult<CheckMachineDTO> checkMachine = resourceApi.getCheckMachine(
                CheckMachineTypeEnum.Gate.getType(), checkReqVO.getMachineId(), 1L);
        if (checkMachine.getData() == null) {
            throw exception(CHECK_MACHINE_NOT_EXIST);
        }
        checkReqVO.setChannelId(checkMachine.getData().getChannelId());
        checkReqVO.setMachineName(checkMachine.getData().getName());
        // 二维码解密
        if (CheckCodeTypeEnum.Voucher_No.getType().equals(checkReqVO.getCodeType())) {
            checkReqVO.setCheckCodes(base64Decode(checkReqVO.getCheckCodes()));
            // 如果为身份证号，则修改codeType为身份证号
            if (IdcardUtil.isValidCard(checkReqVO.getCheckCodes())) {
                checkReqVO.setCodeType(CheckCodeTypeEnum.Card_No.getType());
            }
        }

        return checkCommon(checkReqVO);
    }

    @Override
    public CommonResult<Boolean> checkGateUpdate(TradeCheckUrlVO checkReqVO) {
        try {
            tradeDetailMapper.updateImgByVoucherCode(checkReqVO.getTicketNo(), checkReqVO.getUrl());
            return success(true);
        } catch (Exception e) {
            return error(500, "更新失败" + e.getMessage());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<List<TradeCheckRespVO>> checkPda(TradeCheckReqVO checkReqVO) {
        Assert.isFalse(Objects.isNull(checkReqVO.getMachineId()), () -> exception(MACHINE_ID_NOT_EXIST));

        CommonResult<CheckMachineDTO> checkMachine = resourceApi.getCheckMachine(
                CheckMachineTypeEnum.PDA.getType(), checkReqVO.getMachineId(), null);
        if (checkMachine.getData() == null) {
            throw exception(CHECK_MACHINE_NOT_EXIST);
        }
        checkReqVO.setChannelId(checkMachine.getData().getChannelId());
        checkReqVO.setMachineName(checkMachine.getData().getName());
        return checkCommon(checkReqVO);
    }

    @Override
    public CommonResult<List<PdaCheckStaticRespVO>> pdaCheckStatic(PdaCheckStaticReqVO checkReqVO) {
        if (StringUtils.isBlank(checkReqVO.getBeginTime())) {
            checkReqVO.setBeginTime(DateUtil.formatDate(new Date()) + " 00:00:00");
        }
        if (StringUtils.isBlank(checkReqVO.getEndTime())) {
            checkReqVO.setEndTime(DateUtil.formatDate(new Date()) + " 23:59:59");
        }
        return success(null);
    }

    @Override
    @Cacheable(cacheNames = "pdaCheckTotalCount#10", key = "#dispatchId")
    public CommonResult<Map<String, Object>> pdaCheckTotalCount(String dispatchId) {
        Integer count = tradeCheckMapper.pdaCheckTotalCount(dispatchId);
        Map<String, Object> map = new HashMap<>();
        map.put("num", count);
        return success(map);
    }

    @Override
    public CommonResult<List<PdaCheckTotalStaticRespVO>> pdaCheckTotalStatic(PdaCheckStaticReqVO checkReqVO) {
        if (StringUtils.isBlank(checkReqVO.getBeginTime())) {
            checkReqVO.setBeginTime(DateUtil.formatDate(new Date()) + " 00:00:00");
        }
        if (StringUtils.isBlank(checkReqVO.getEndTime())) {
            checkReqVO.setEndTime(DateUtil.formatDate(new Date()) + " 23:59:59");
        }
        return success(null);
    }


    @Override
    public CommonResult<List<TradeCheckRespVO>> checkApplet(TradeCheckReqVO checkReqVO) {
        // 证件号解密
        if (CheckCodeTypeEnum.Card_No.getType().equals(checkReqVO.getCodeType())) {
            checkReqVO.setCheckCodes(base64Decode(checkReqVO.getCheckCodes()));
        }
        List<TradeCheckRespVO> result = checkCommon(checkReqVO).getData();
        // 标记0成功 1失败 返回失败结果
        if (result != null) {
            result.forEach(r -> {
                r.setIsSuccess(r.getIsSuccess() == 0 ? 1 : 0);
                r.setIsPreSuccess(r.getIsPreSuccess() == 0 ? 1 : 0);
            });
        }
        List<TradeCheckRespVO> failResult = null;
        if (result != null) {
            failResult = result.stream().filter(item -> item.getIsSuccess() != 0).collect(Collectors.toList());
        }
        return failResult != null ? success(null, "核销成功") : success(null);
    }

    @Override
    public CommonResult<List<TradeCheckRespVO>> checkOther(TradeCheckReqVO checkReqVO) {
        String[] checkCodes = checkReqVO.getCheckCodes().split(",");
        //平台订单号查询旅行社订单信息
        List<TradeDetailDO> listByVoucherCodeOtc = tradeDetailMapper.getListByVoucherCodeOtc(Arrays.asList(checkCodes));
        if (!listByVoucherCodeOtc.isEmpty()) {
            for (TradeDetailDO tradeDetailDO : listByVoucherCodeOtc) {
                checkReqVO.setCheckCodes(checkReqVO.getCheckCodes() + "," + tradeDetailDO.getVoucherCode());
            }
        } else {
            //如果是小程序或者内部旅行社订单，则需要查询平台订单信息一起核销
            List<TradeDetailDO> listByVoucherCodePlat = tradeDetailMapper.getListByVoucherCodePlat(Arrays.asList(checkCodes));
            if (!listByVoucherCodePlat.isEmpty()) {
                for (TradeDetailDO tradeDetailDO : listByVoucherCodePlat) {
                    checkReqVO.setCheckCodes(checkReqVO.getCheckCodes() + "," + tradeDetailDO.getVoucherCode());
                }
            }
        }
        return checkCommon(checkReqVO);
    }

    /**
     * 证件号解密
     *
     * @param checkCode 证件号
     * @return 解密后的证件号
     */
    private String base64Decode(String checkCode) {
        Pattern compile = Pattern.compile("[0-9a-zA-z]+");
        if (checkCode.contains(",")) {
            StringJoiner joiner = new StringJoiner(",");
            String[] split = checkCode.split(",");
            for (String str : split) {
                String s = Base64.decodeStr(str);
                if (compile.matcher(s).matches()) {
                    // 解码后比较原字符串长度，如果大于原字符串长度，说明解码失败，返回原字符串
                    joiner.add(s.length() > str.length() ? str : s);
                } else {
                    // 如果解码后不是由字母和数字组成的，返回原字符串
                    joiner.add(str);
                }
            }
            return joiner.toString();
        } else {
            String s = Base64.decodeStr(checkCode);
            if (compile.matcher(s).matches()) {
                // 解码后比较原字符串长度，如果大于原字符串长度，说明解码失败，返回原字符串
                return s.length() > checkCode.length() ? checkCode : s;
            } else {
                // 如果解码后不是由字母和数字组成的，返回原字符串
                return checkCode;
            }
        }
    }

    @Override
    public CommonResult<?> queryCheckPage(TradeCheckPageReqVO reqVO) {
        reqVO.setMachineId(IPUtils.getIpAddr());
        IPage<CheckRespVO> iPage = MyBatisUtils.buildPage(reqVO);
        IPage<CheckRespVO> page = tradeCheckMapper.querySimpleCheckPage(iPage, reqVO);
        page.getRecords().forEach(checkRespVO -> {
            checkRespVO.setTradeDetailRespVO(tradeOrderRepositoryService.getTradeDetailByCheckId(checkRespVO.getId()));
        });
        PageResult<CheckRespVO> pageResult = new PageResult<>(page.getRecords(), page.getTotal());
        return success(pageResult);
    }


    @Override
    public CommonResult<?> querySimpleCheckPage(TradeCheckPageReqVO reqVO, boolean needDetail) {
        IPage<CheckRespVO> iPage = MyBatisUtils.buildPage(reqVO);
        IPage<CheckRespVO> page = tradeCheckMapper.querySimpleCheckPage(iPage, reqVO);
        if (needDetail) {
            page.getRecords().forEach(checkRespVO -> checkRespVO.setTradeDetailRespVO(
                    tradeOrderRepositoryService.getTradeDetailByCheckId(checkRespVO.getId())
            ));
        }
        return success(new PageResult<>(page.getRecords(), page.getTotal()));
    }

    @Override
    public PageResult<CheckRespVO> querySimpleCheckList(TradeCheckPageReqVO reqVO, boolean needDetail) {
        IPage<CheckRespVO> iPage = MyBatisUtils.buildPage(reqVO);
        IPage<CheckRespVO> page = tradeCheckMapper.querySimpleCheckPage(iPage, reqVO);
        if (needDetail) {
            page.getRecords().forEach(checkRespVO -> checkRespVO.setTradeDetailRespVO(
                    tradeOrderRepositoryService.getTradeDetailByCheckId(checkRespVO.getId())
            ));
        }
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public CommonResult<?> queryCheckDetailList(Long checkId) {
        return success(tradeOrderRepositoryService.getTradeDetailByCheckId(checkId));
    }


}

