package cn.freemud.management.service.handle;

import cn.freemud.management.entities.dto.request.coupon.CodeInfoQueryDto;
import cn.freemud.management.entities.dto.response.coupon.CouponBaseResponse;
import cn.freemud.management.enums.CouponStatus;
import cn.freemud.management.thirdparty.CouponQueryClient;
import cn.freemud.management.thirdparty.request.coupon.CodeInfoQueryReq;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.log.ApiLog;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * &copy; All rights Reserved
 *
 * @author wénkǎi.zhāng 2024-01-02
 * @since 1.0
 */
@Component
@RequiredArgsConstructor
public class CouponQueryHandle {
    private final CouponQueryClient couponQueryClient;

    private final int SUCCESS_CODE = 100;

    /**
     * 查询券信息
     * <pre>
     *   1. 本方法会忽略查询失败的券，因此可能传入的券号不一定都能在返回列表中找到与之对应的券信息
     *   2. 同时，本方法会对入参中的codes去重，券码接口对已归档的券也不会返回，基于本条和上一条，
     *   应注意传入集合的size可能和返回列表的size不同，也许是正常现象
     *   3. 本方法不保证返回的券信息顺序和入参的券号顺序相同
     * </pre>
     * @param partnerId
     * @param codes 券号列表，支持 非码券/微信商家券/支付宝商家券
     * @return 对券号列表去重后，成功查到的券信息列表
     */
    public List<CodeInfoQueryDto> queryCodesInfo(String partnerId, Collection<String> codes) {
        List<CodeInfoQueryDto> result = new ArrayList<>();

        CodeInfoQueryReq request = new CodeInfoQueryReq();
        request.setPartnerId(partnerId);

        // 券码接口最大支持每次10个券号
        Lists.partition(new ArrayList<>(new HashSet<>(codes)), 10).forEach(subList -> {
            // 注意：如果改成并发调用，这里不能直接复用request
            request.setCodes(subList);
            try {
                CouponBaseResponse<List<CodeInfoQueryDto>> resp = couponQueryClient.queryCodesInfo(request);
                if (!Objects.equals(SUCCESS_CODE, resp.getStatusCode()) || CollectionUtils.isEmpty(resp.getResult())) {
                    ApiLog.warnMessage("优惠券信息查询失败：{} {}", JSONObject.toJSONString(request), JSONObject.toJSONString(resp));
                    return;
                }
                result.addAll(resp.getResult());
            } catch (Throwable e) {
                ApiLog.warnMessage("优惠券信息查询异常：{} {}", e.getMessage(), JSONObject.toJSONString(request));
            }
        });

        return result;
    }


    /**
     * 指定一组券号，判断这些券号中是否存在已使用的券
     * <pre></pre>
     * @param partnerId
     * @param couponCodes
     * @return 如果有一张或多张券没查到、或已使用、或已部分使用、或已锁定，返回true
     */
    public boolean isCouponUsed(String partnerId, Collection<String> couponCodes) {
        boolean used;
        List<CodeInfoQueryDto> codeInfoQueryDtos = this.queryCodesInfo(partnerId, couponCodes);
        // 以下条件任意一个成立，说明券已使用：
        // 1. 返回的数量和查询的不一致
        // 2. 券状态不是 0
        // 3. 存在锁定的券（剩余核销次数!=总核销次数）
        used = couponCodes.size() != codeInfoQueryDtos.size()
                || codeInfoQueryDtos.stream().anyMatch(o -> {
            return !CouponStatus.STATUS_0.getCode().equals(o.getState())
                    || !Objects.equals(o.getMaxLeftAvailableTimes(), o.getCouponUseRule().getMaxRedeemTimes());
        });
        return used;
    }
}
