package com.liquidnet.service.adam.service.caomei;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.liquidnet.service.adam.dto.vo.AdamRealInfoVo;
import com.liquidnet.service.adam.entity.AdamCaomeiBadge;
import com.liquidnet.service.adam.entity.AdamCaomeiBadgeApplyRecord;
import com.liquidnet.service.adam.mapper.AdamCaomeiBadgeApplyRecordMapper;
import com.liquidnet.service.adam.mapper.AdamCaomeiBadgeMapper;
import com.liquidnet.service.adam.service.AdamRdmService;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 草莓徽章「领取资格」判断：护照首页货架展示（是否可点领取、是否补签待审）
 * 与 {@code POST caomei/badge/claim} 演出徽章校验共用同一套规则。
 * <p>
 * 不负责写 Redis/MQ；发放见 {@link CaomeiBadgeGrantService}。
 */
@Service
public class CaomeiBadgeEligibilityService {

    /** 徽章类型：签证页（仅 home 静默发放，不可 claim） */
    private static final int BADGE_TYPE_VISA = 4;

    @Autowired
    private AdamCaomeiBadgeApplyRecordMapper badgeApplyRecordMapper;
    @Autowired
    private AdamCaomeiBadgeMapper adamCaomeiBadgeMapper;
    @Autowired
    private AdamRdmService adamRdmService;

    /**
     * 加载用户补签状态，用于 home 货架 {@code allBadges} 的 claimable / applyPending。
     * <p>
     * 只查 auditStatus 为 0（待审）、1（通过）的记录；驳回(2) 不参与。
     * 补签记录若未填 performanceId，会用 {@code published} 里 badgeId→performanceId 兜底，
     * 以便按「场次」聚合待审/通过状态。
     *
     * @param uid       当前用户 ID
     * @param published 已上架徽章全量列表（来自 published Redis），用于 performanceId 兜底
     */
    public CaomeiBadgeApplyStatus loadApplyBadgeStatus(String uid, List<AdamCaomeiBadge> published) {
        // 徽章ID 演出ID Map
        Map<String, String> badgeIdToPerformanceId = new HashMap<>();
        if (published != null) {
            for (AdamCaomeiBadge b : published) {
                if (b != null && StringUtils.isNotBlank(b.getBadgeId())) {
                    badgeIdToPerformanceId.put(b.getBadgeId(), StringUtils.trimToEmpty(b.getPerformanceId()));
                }
            }
        }
        // 查询用户提交的补签申请（0 待审核、1 已通过）
        List<AdamCaomeiBadgeApplyRecord> applyRecords = badgeApplyRecordMapper.selectList(
                Wrappers.lambdaQuery(AdamCaomeiBadgeApplyRecord.class)
                        .eq(AdamCaomeiBadgeApplyRecord::getUserId, uid)
                        .in(AdamCaomeiBadgeApplyRecord::getAuditStatus, 0, 1)
        );
        Set<String> passedApplyBadgeIds = new HashSet<>(); // 补签通过的徽章ID
        Set<String> pendingApplyBadgeIds = new HashSet<>(); // 补签中的徽章ID
        Set<String> passedApplyPerformanceIds = new HashSet<>(); // 补签通过的演出ID
        Set<String> pendingApplyPerformanceIds = new HashSet<>(); // 补签中的演出ID
        if (applyRecords != null) {
            for (AdamCaomeiBadgeApplyRecord r : applyRecords) {
                if (r == null || StringUtils.isBlank(r.getBadgeId()) || r.getAuditStatus() == null) {
                    continue;
                }
                String perf = StringUtils.trimToEmpty(r.getPerformanceId());
                if (StringUtils.isBlank(perf)) {
                    perf = StringUtils.trimToEmpty(badgeIdToPerformanceId.get(r.getBadgeId()));
                }
                if (r.getAuditStatus() == 1) {
                    passedApplyBadgeIds.add(r.getBadgeId());
                    if (StringUtils.isNotBlank(perf)) {
                        passedApplyPerformanceIds.add(perf);
                    }
                } else if (r.getAuditStatus() == 0) {
                    pendingApplyBadgeIds.add(r.getBadgeId());
                    if (StringUtils.isNotBlank(perf)) {
                        pendingApplyPerformanceIds.add(perf);
                    }
                }
            }
        }
        return new CaomeiBadgeApplyStatus(
                passedApplyBadgeIds,
                pendingApplyBadgeIds,
                passedApplyPerformanceIds,
                pendingApplyPerformanceIds
        );
    }

    /**
     * 为本次 claim 请求中的 type=2 徽章构建校验上下文（实名、购票场次、补签通过、同场 badge 映射）。
     * <p>
     * 须在 {@link #canClaimPerformanceBadge} / {@link #resolveClaimSourceForType2} 之前调用一次。
     *
     * @param uid                 用户 ID
     * @param type2BadgesInRequest 本次请求要认领的徽章列表（可含 type=1，内部只取 type=2 的 performanceId）
     * @return {@code realNameOk=false} 表示未实名，不可领任何 type=2
     */
    public Type2ClaimContext buildType2ClaimContext(String uid, List<AdamCaomeiBadge> type2BadgesInRequest) {
        AdamRealInfoVo real = adamRdmService.getRealInfoVoByUidPlain(uid);
        if (real == null || real.getState() == null || real.getState() != 1 || StringUtils.isBlank(real.getIdCard())) {
            return Type2ClaimContext.notEligible();
        }
        List<String> paidPerformanceIds = adamRdmService.getPaidPerformanceIdsByIdCard(real.getIdCard());
        Set<String> paidPerformanceSet = paidPerformanceIds == null
                ? Collections.emptySet()
                : new HashSet<>(paidPerformanceIds);

        List<AdamCaomeiBadgeApplyRecord> passedApplyRecords = badgeApplyRecordMapper.selectList(
                Wrappers.lambdaQuery(AdamCaomeiBadgeApplyRecord.class)
                        .eq(AdamCaomeiBadgeApplyRecord::getUserId, uid)
                        .eq(AdamCaomeiBadgeApplyRecord::getAuditStatus, 1)
        );
        Set<String> passedApplyBadgeIds = new HashSet<>();
        Set<String> passedApplyPerformanceIds = new HashSet<>();
        if (passedApplyRecords != null) {
            for (AdamCaomeiBadgeApplyRecord r : passedApplyRecords) {
                if (r == null) {
                    continue;
                }
                if (StringUtils.isNotBlank(r.getBadgeId())) {
                    passedApplyBadgeIds.add(r.getBadgeId());
                }
                if (StringUtils.isNotBlank(r.getPerformanceId())) {
                    passedApplyPerformanceIds.add(r.getPerformanceId());
                }
            }
        }

        Map<String, Set<String>> perfAllBadgeIds = Collections.emptyMap();
        if (type2BadgesInRequest != null && !type2BadgesInRequest.isEmpty()) {
            Set<String> targetPerfIds = type2BadgesInRequest.stream()
                    .filter(b -> b != null && b.getType() != null && b.getType() == 2)
                    .map(AdamCaomeiBadge::getPerformanceId)
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.toSet());
            if (!targetPerfIds.isEmpty()) {
                List<AdamCaomeiBadge> perfBadges = adamCaomeiBadgeMapper.selectList(
                        Wrappers.lambdaQuery(AdamCaomeiBadge.class)
                                .eq(AdamCaomeiBadge::getType, 2)
                                .in(AdamCaomeiBadge::getPerformanceId, targetPerfIds)
                );
                perfAllBadgeIds = perfBadges == null ? Collections.emptyMap() : perfBadges.stream()
                        .filter(b -> StringUtils.isNotBlank(b.getPerformanceId()) && StringUtils.isNotBlank(b.getBadgeId()))
                        .collect(Collectors.groupingBy(AdamCaomeiBadge::getPerformanceId,
                                Collectors.mapping(AdamCaomeiBadge::getBadgeId, Collectors.toSet())));
            }
        }
        return new Type2ClaimContext(true, paidPerformanceSet, passedApplyBadgeIds, passedApplyPerformanceIds, perfAllBadgeIds);
    }

    /**
     * 判断单枚 type=2 演出纪念徽章是否允许认领。
     * <p>
     * 满足其一即可：身份证下有该场次购票；该场次补签已通过；同场次任一 type=2 徽章补签已通过。
     *
     * @param badge 待认领配置（须 type=2）
     * @param ctx   {@link #buildType2ClaimContext} 的返回值
     */
    public boolean canClaimPerformanceBadge(AdamCaomeiBadge badge, Type2ClaimContext ctx) {
        if (badge == null || ctx == null || !ctx.isRealNameOk()) {
            return false;
        }
        String perfId = StringUtils.trimToEmpty(badge.getPerformanceId());
        boolean hasPaidRecord = StringUtils.isNotBlank(perfId) && ctx.getPaidPerformanceSet().contains(perfId);
        if (hasPaidRecord) {
            return true;
        }
        if (StringUtils.isBlank(perfId)) {
            return false;
        }
        if (ctx.getPassedApplyPerformanceIds().contains(perfId)) {
            return true;
        }
        Set<String> badgeIdSet = ctx.getPerfAllBadgeIds().getOrDefault(perfId, Collections.emptySet());
        return badgeIdSet.stream().anyMatch(id -> ctx.getPassedApplyBadgeIds().contains(id));
    }

    /**
     * 解析 type=2 认领落库时的 source：有购票记录为 2，否则视为补签通过为 3。
     *
     * @param badge 当前认领的 type=2 徽章
     * @param ctx   已构建的 Type2 上下文
     */
    public int resolveClaimSourceForType2(AdamCaomeiBadge badge, Type2ClaimContext ctx) {
        String perfId = StringUtils.trimToEmpty(badge.getPerformanceId());
        boolean hasPaid = StringUtils.isNotBlank(perfId) && ctx.getPaidPerformanceSet().contains(perfId);
        return hasPaid ? 2 : 3;
    }

    /**
     * 计算首页货架单枚徽章的交互状态（未领取时是否显示可领、是否补签待审）。
     * <p>
     * type=1：已绑护照即可 claimable（用于后上架补领）；type=2：购票或补签通过；
     * type=3/4：不可自助领取（4 由 home 静默发，不在货架展示）。
     *
     * @param badge               货架上的徽章配置
     * @param claimed             用户是否已在 user 缓存/库中拥有该 badgeId
     * @param paidPerformanceIds  实名身份证下的已购场次 ID 列表（home 已查）
     * @param applyStatus         {@link #loadApplyBadgeStatus} 结果
     */
    public ShelfInteractState resolveShelfInteract(AdamCaomeiBadge badge,
                                                   boolean claimed,
                                                   List<String> paidPerformanceIds,
                                                   CaomeiBadgeApplyStatus applyStatus) {
        ShelfInteractState state = new ShelfInteractState();
        if (claimed) {
            state.setClaimable(false);
            state.setApplyPending(false);
            return state;
        }
        int type = badge.getType() == null ? 0 : badge.getType();
        String perfId = StringUtils.defaultString(badge.getPerformanceId());
        if (type == 1) {
            state.setClaimable(true);
        } else if (type == 2) {
            boolean canClaimByPaid = paidPerformanceIds != null && paidPerformanceIds.contains(badge.getPerformanceId());
            boolean canClaimByApplyThisBadge = applyStatus.getPassedApplyBadgeIds().contains(badge.getBadgeId());
            boolean canClaimByApplyThisPerf = StringUtils.isNotBlank(perfId)
                    && applyStatus.getPassedApplyPerformanceIds().contains(perfId);
            state.setClaimable(canClaimByPaid || canClaimByApplyThisBadge || canClaimByApplyThisPerf);
            boolean pendingThisBadge = applyStatus.getPendingApplyBadgeIds().contains(badge.getBadgeId());
            boolean pendingThisPerf = StringUtils.isNotBlank(perfId)
                    && applyStatus.getPendingApplyPerformanceIds().contains(perfId);
            state.setApplyPending(pendingThisBadge || pendingThisPerf);
        } else {
            state.setClaimable(false);
        }
        return state;
    }

    /** 是否签证页 type=4（用于 home 响应拆分 claimedBadges / visaBadges） */
    public static boolean isVisaBadgeType(Integer type) {
        return type != null && type == BADGE_TYPE_VISA;
    }

    /**
     * type=2 批量认领时的只读上下文，避免 claim 循环内重复查实名/购票/补签。
     */
    @Getter
    public static final class Type2ClaimContext {

        /** 是否已实名（state=1 且有身份证号） */
        private final boolean realNameOk;
        /** 身份证下已支付订单关联的场次 ID */
        private final Set<String> paidPerformanceSet;
        /** 补签审核通过的 badgeId */
        private final Set<String> passedApplyBadgeIds;
        /** 补签审核通过的 performanceId */
        private final Set<String> passedApplyPerformanceIds;
        /**
         * 场次 → 该场次下所有 type=2 的 badgeId 集合；
         * 用于「同场次任一徽章补签通过则本场次均可领」规则。
         */
        private final Map<String, Set<String>> perfAllBadgeIds;

        private Type2ClaimContext(boolean realNameOk,
                                  Set<String> paidPerformanceSet,
                                  Set<String> passedApplyBadgeIds,
                                  Set<String> passedApplyPerformanceIds,
                                  Map<String, Set<String>> perfAllBadgeIds) {
            this.realNameOk = realNameOk;
            this.paidPerformanceSet = paidPerformanceSet;
            this.passedApplyBadgeIds = passedApplyBadgeIds;
            this.passedApplyPerformanceIds = passedApplyPerformanceIds;
            this.perfAllBadgeIds = perfAllBadgeIds;
        }

        /** 未实名时的空上下文，{@link #canClaimPerformanceBadge} 将全部返回 false */
        static Type2ClaimContext notEligible() {
            return new Type2ClaimContext(false, Collections.emptySet(), Collections.emptySet(),
                    Collections.emptySet(), Collections.emptyMap());
        }
    }

    /**
     * 首页货架项的前端交互标记（对应 {@link com.liquidnet.service.adam.dto.vo.AdamCaomeiPassportBadgeShelfItemVo}）。
     */
    @Getter
    @Setter
    public static final class ShelfInteractState {
        /** 未领取时是否展示为可点击认领 */
        private boolean claimable;
        /** 是否展示补签审核中（仅 type=2 有意义） */
        private boolean applyPending;
    }
}
