package com.liquidnet.service.adam.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.adam.dto.AdamCaomeiPassportUserBadgeDto;
import com.liquidnet.service.adam.dto.vo.*;
import com.liquidnet.service.adam.entity.AdamCaomeiBadge;
import com.liquidnet.service.adam.entity.AdamCaomeiBadgeApplyRecord;
import com.liquidnet.service.adam.entity.AdamCaomeiPassport;
import com.liquidnet.service.adam.mapper.AdamCaomeiBadgeApplyRecordMapper;
import com.liquidnet.service.adam.mapper.AdamCaomeiBadgeMapper;
import com.liquidnet.service.adam.mapper.AdamCaomeiPassportMapper;
import com.liquidnet.service.adam.service.AdamRdmService;
import com.liquidnet.service.adam.service.IAdamCaomeiPassportUserService;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AdamCaomeiPassportUserServiceImpl implements IAdamCaomeiPassportUserService {

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseDto<List<AdamCaomeiPassportUserClaimedBadgeVo>> bindPassport(String passportNo) {
        String uid = CurrentUtil.getCurrentUid();

        // 1. 先校验护照信息是否满足绑定条件
        AdamCaomeiPassport passport = adamCaomeiPassportMapper.selectOne(
                Wrappers.lambdaQuery(AdamCaomeiPassport.class)
                        .eq(AdamCaomeiPassport::getPassportNo, passportNo.trim()));

        if (passport == null) {
            log.error("[bindPassport] 未查询到护照信息, passportSn: {}", passportNo);
            return ResponseDto.failure(ErrorMapping.get("10600"));
        }

        Integer st = passport.getStatus();
        if (st != null && st == 2) {
            log.error("[bindPassport] 护照已作废, passportSn: {}", passportNo);
            return ResponseDto.failure(ErrorMapping.get("10601"));
        }

        if (st != null && st == 1) {
            if (uid.equals(StringUtils.trimToEmpty(passport.getUserId()))) {
                return ResponseDto.failure(ErrorMapping.get("10606")); // 提示无需重复绑定
            }
            log.error("[bindPassport] 护照已被其他账号绑定, passportSn: {}", passportNo);
            return ResponseDto.failure(ErrorMapping.get("10602"));
        }

        // 2. 校验当前用户是否已经绑定过其他护照
        AdamCaomeiPassport userExistsPassport = findBoundPassportForUser(uid);
        if (userExistsPassport != null && !passportNo.equals(userExistsPassport.getPassportNo())) {
            log.error("[bindPassport] 已绑定护照, uid: {}, existsPassportSn: {}, newPassportSn: {}", uid, userExistsPassport.getPassportNo(), passportNo);
            return ResponseDto.failure(ErrorMapping.get("10603"));
        }

        // 3. 尝试原子更新绑定状态 (仅当 status = 0 时才能更新成功)
        int updatedRows = adamCaomeiPassportMapper.bindPassportAtomic(passportNo.trim(), uid);

        if (updatedRows > 0) {
            // 4. 优先复用已上架徽章缓存，再筛选护照纪念徽章(type=1)，用于批量发放和返回给前端弹窗
            List<AdamCaomeiBadge> publishedBadges = adamRdmService.getPublishedCaomeiBadges();
            if (publishedBadges == null) {
                publishedBadges = new ArrayList<>();
            }
            List<AdamCaomeiBadge> passportTypeBadges = publishedBadges.stream()
                    .filter(b -> b.getType() != null && b.getType() == 1)
                    .collect(Collectors.toList());
            List<String> badgeIds = passportTypeBadges.stream()
                    .map(AdamCaomeiBadge::getBadgeId)
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.toList());
            Date grantAt = new Date();
            if (!badgeIds.isEmpty()) {
                adamCaomeiBadgeMapper.insertUserBadgesBatch(uid, badgeIds, 1, grantAt);
            }
            // 清理用户徽章缓存，下次读取首页时回源并重建
            adamRdmService.delUserCaomeiBadgesByUid(uid);

            // 5. 返回本次绑定场景下的护照类型徽章列表（用于前端弹窗）
            List<AdamCaomeiPassportUserClaimedBadgeVo> grantedBadges = passportTypeBadges.stream().map(b -> {
                AdamCaomeiPassportUserClaimedBadgeVo v = new AdamCaomeiPassportUserClaimedBadgeVo();
                v.setBadgeId(b.getBadgeId());
                v.setName(StringUtils.defaultString(b.getName()));
                v.setIcon(StringUtils.defaultString(b.getIcon()));
                v.setType(b.getType());
                v.setClaimedAt(grantAt);
                v.setSource(1);
                return v;
            }).collect(Collectors.toList());
            log.info("[bindPassport] 护照绑定成功, uid: {}, passportSn: {}", uid, passportNo);
            return ResponseDto.success(grantedBadges);
        }

        // 6. 如果原子性修改未成功，说明在并发情况下被别人抢先绑定了
        log.error("[bindPassport] 并发绑定失败，护照已被抢占, passportSn: {}", passportNo);
        return ResponseDto.failure(ErrorMapping.get("10602"));
    }

    @Override
    public ResponseDto<AdamCaomeiPassportHomeVo> getPassportHome() {
        String uid = CurrentUtil.getCurrentUid();
        log.info("[getPassportHome] 开始获取护照首页数据, uid: {}", uid);

        // 4. 获取用户当前绑定的护照信息
        AdamCaomeiPassport bound = findBoundPassportForUser(uid);
        if (null == bound) {
            log.error("[getPassportHome] 用户未绑定护照, uid: {}", uid);
            return ResponseDto.failure(ErrorMapping.get("10604")); // 未绑定护照
        }

        // 1. 初始化返回对象
        AdamCaomeiPassportHomeVo home = new AdamCaomeiPassportHomeVo();
        AdamCaomeiPassportUserCardVo card = new AdamCaomeiPassportUserCardVo();
        card.setPassportBound(true);
        card.setPassportNo(bound.getPassportNo());
        card.setPassportClaimedAt(bound.getBoundAt());
        home.setUserCard(card);

        // 2. 获取用户基本信息(头像、昵称)
        AdamUserInfoVo userInfo = adamRdmService.getUserInfoVoByUid(uid);
        if (userInfo != null) {
            card.setAvatar(StringUtils.defaultString(userInfo.getAvatar()));
            card.setNickname(StringUtils.defaultString(userInfo.getNickname()));
        } else {
            card.setAvatar("");
            card.setNickname("");
        }

        // 3. 获取用户实名认证信息
        AdamRealInfoVo real = adamRdmService.getRealInfoVoByUidPlain(uid);
        String idCard = null;
        boolean isRealNameVerified = false;
        if (real != null && real.getState() != null && real.getState() == 1 && real.getType() == 1) {
            isRealNameVerified = true;
            idCard = real.getIdCard();
        }
        card.setRealNameVerified(isRealNameVerified);
        log.info("[getPassportHome] 实名认证状态, uid: {}, 是否已实名: {}, 是否有身份证号: {}",
                uid, isRealNameVerified, StringUtils.isNotBlank(idCard));

        // 5. 查询用户购买过的演出ID列表 (用于判断演出徽章是否可认领)
        final List<String> paidPerformanceIds = StringUtils.isNotBlank(idCard)
                ? adamCaomeiBadgeMapper.selectPaidPerformanceIdsByIdCard(idCard)
                : new ArrayList<>();
        log.info("[getPassportHome] 用户已支付的演出订单数量, uid: {}, 数量: {}", uid, paidPerformanceIds.size());

        // 5.1 查询用户补签审核已通过的徽章（用于判断演出徽章是否可认领）
        Set<String> passedApplyBadgeIds = badgeApplyRecordMapper.selectList(
                Wrappers.lambdaQuery(AdamCaomeiBadgeApplyRecord.class)
                        .eq(AdamCaomeiBadgeApplyRecord::getUserId, uid)
                        .eq(AdamCaomeiBadgeApplyRecord::getAuditStatus, 1)
        ).stream().map(AdamCaomeiBadgeApplyRecord::getBadgeId)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());

        // 5.2 查询用户补签待审核的徽章（用于前端展示“审核中”状态）
        Set<String> pendingApplyBadgeIds = badgeApplyRecordMapper.selectList(
                Wrappers.lambdaQuery(AdamCaomeiBadgeApplyRecord.class)
                        .eq(AdamCaomeiBadgeApplyRecord::getUserId, uid)
                        .eq(AdamCaomeiBadgeApplyRecord::getAuditStatus, 0)
        ).stream().map(AdamCaomeiBadgeApplyRecord::getBadgeId)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());

        // 6. 查询用户已认领的所有徽章记录 (用于展示徽章墙)
        List<AdamCaomeiPassportUserBadgeDto> rows = adamRdmService.getUserCaomeiBadgesByUid(uid);
        if (rows == null) {
            rows = new ArrayList<>();
        }
        List<AdamCaomeiPassportUserClaimedBadgeVo> claimed = rows.stream().map(r -> {
            AdamCaomeiPassportUserClaimedBadgeVo v = new AdamCaomeiPassportUserClaimedBadgeVo();
            v.setBadgeId(r.getBadgeId());
            v.setName(StringUtils.defaultString(r.getBadgeName()));
            v.setIcon(StringUtils.defaultString(r.getIcon()));
            v.setType(r.getType());
            v.setClaimedAt(r.getClaimedAt());
            v.setSource(r.getSource());
            return v;
        }).collect(Collectors.toList());
        home.setClaimedBadges(claimed);
        log.info("[getPassportHome] 用户已认领的徽章数量, uid: {}, 数量: {}", uid, claimed.size());

        // 转换为 Map 方便后续匹配货架上的徽章是否已认领
        Map<String, AdamCaomeiPassportUserBadgeDto> claimedMap = rows.stream()
                .filter(r -> StringUtils.isNotBlank(r.getBadgeId()))
                .collect(Collectors.toMap(AdamCaomeiPassportUserBadgeDto::getBadgeId, Function.identity(), (a, b) -> a));

        // 7. 查询所有已上架的徽章配置，并按类型升序、排序值降序、ID降序排序
        List<AdamCaomeiBadge> published = adamRdmService.getPublishedCaomeiBadges();
        if (published == null) {
            published = new ArrayList<>();
        }
        log.info("[getPassportHome] 系统已上架的徽章数量, uid: {}, 数量: {}", uid, published.size());

        // 8. 组装全部上架徽章列表 (扁平结构，前端按 type 筛选展示)
        List<AdamCaomeiPassportBadgeShelfItemVo> allBadges = published.stream()
                .map(b -> toShelfItem(b, claimedMap, paidPerformanceIds, passedApplyBadgeIds, pendingApplyBadgeIds))
                .collect(Collectors.toList());

        home.setAllBadges(allBadges);
        log.info("[getPassportHome] 获取护照首页数据成功, uid: {}", uid);
        return ResponseDto.success(home);
    }

    /**
     * @param b                  徽章信息
     * @param claimedMap         用户已领取的徽章
     * @param paidPerformanceIds 当前账号实名身份证号码购买的演出IDs
     * @param passedApplyBadgeIds 补签审核已通过的徽章ID集合
     * @param pendingApplyBadgeIds 补签待审核的徽章ID集合
     * @return
     */
    private static AdamCaomeiPassportBadgeShelfItemVo toShelfItem(AdamCaomeiBadge b,
                                                                  Map<String, AdamCaomeiPassportUserBadgeDto> claimedMap,
                                                                  List<String> paidPerformanceIds,
                                                                  Set<String> passedApplyBadgeIds,
                                                                  Set<String> pendingApplyBadgeIds) {
        AdamCaomeiPassportBadgeShelfItemVo v = new AdamCaomeiPassportBadgeShelfItemVo();
        v.setBadgeId(b.getBadgeId());
        v.setName(StringUtils.defaultString(b.getName()));
        v.setIcon(StringUtils.defaultString(b.getIcon()));
        v.setType(b.getType());
        v.setPerformanceId(StringUtils.defaultString(b.getPerformanceId()));
        v.setApplyPending(false);

        // 判断当前徽章是否已认领
        AdamCaomeiPassportUserBadgeDto got = claimedMap.get(b.getBadgeId());
        boolean claimed = got != null;
        v.setClaimed(claimed);
        v.setClaimedAt(claimed ? got.getClaimedAt() : null);

        int type = b.getType() == null ? 0 : b.getType();

        // 针对未认领的徽章，根据类型判断是否可认领 (claimable)
        if (!claimed) {
            if (type == 1) {
                // 护照纪念徽章：只要绑定了护照，就可认领（通常是绑定时漏发或后来新上架的）
                v.setClaimable(true);
            } else if (type == 2) {
                // 演出纪念徽章：有购票记录或补签审核通过即可认领
                boolean canClaimByPaid = paidPerformanceIds != null && paidPerformanceIds.contains(b.getPerformanceId());
                boolean canClaimByApply = passedApplyBadgeIds != null && passedApplyBadgeIds.contains(b.getBadgeId());
                v.setClaimable(canClaimByPaid || canClaimByApply);
                v.setApplyPending(pendingApplyBadgeIds != null && pendingApplyBadgeIds.contains(b.getBadgeId()));
            } else if (type == 3) {
                // 特殊徽章：不可自助领取，需要提示用户
                v.setClaimable(false);
            }
        } else {
            // 已认领的徽章，可认领状态置为 false
            v.setClaimable(false);
        }
        return v;
    }

    private AdamCaomeiPassport findBoundPassportForUser(String uid) {
        if (StringUtils.isBlank(uid)) {
            return null;
        }
        return adamCaomeiPassportMapper.selectOne(
                Wrappers.lambdaQuery(AdamCaomeiPassport.class)
                        .eq(AdamCaomeiPassport::getUserId, uid)
                        .eq(AdamCaomeiPassport::getStatus, 1)
                        .last("limit 1")
        );
    }
}
