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.AdamCaomeiPassportBadgeShelfItemVo;
import com.liquidnet.service.adam.dto.vo.AdamCaomeiPassportHomeVo;
import com.liquidnet.service.adam.dto.vo.AdamCaomeiPassportUserCardVo;
import com.liquidnet.service.adam.dto.vo.AdamCaomeiPassportUserClaimedBadgeVo;
import com.liquidnet.service.adam.dto.vo.AdamRealInfoVo;
import com.liquidnet.service.adam.dto.vo.AdamUserInfoVo;
import com.liquidnet.service.adam.entity.AdamCaomeiBadge;
import com.liquidnet.service.adam.entity.AdamCaomeiPassport;
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.*;
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 AdamRdmService adamRdmService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseDto<String> 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)
            adamCaomeiBadgeMapper.insertPassportBindingBadgesForUser(uid);
            log.info("[bindPassport] 护照绑定成功, uid: {}, passportSn: {}", uid, passportNo);
            return ResponseDto.success(passportNo);
        }

        // 5. 如果原子性修改未成功，说明在并发情况下被别人抢先绑定了
        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);

        // 1. 初始化返回对象
        AdamCaomeiPassportHomeVo home = new AdamCaomeiPassportHomeVo();
        AdamCaomeiPassportUserCardVo card = new AdamCaomeiPassportUserCardVo();
        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));

        // 4. 获取用户当前绑定的护照信息
        AdamCaomeiPassport bound = findBoundPassportForUser(uid);
        boolean isPassportBound = bound != null;
        if (isPassportBound) {
            card.setPassportBound(true);
            card.setPassportNo(bound.getPassportNo());
        } else {
            card.setPassportBound(false);
            card.setPassportNo("");
        }
        log.info("[getPassportHome] 护照绑定状态, uid: {}, 是否已绑定: {}, 护照编号: {}", uid, isPassportBound, card.getPassportNo());

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

        // 6. 查询用户已认领的所有徽章记录 (用于展示徽章墙)
        List<AdamCaomeiPassportUserBadgeDto> rows = adamCaomeiPassportMapper.selectUserBadgesByUid(uid);
        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 = adamCaomeiBadgeMapper.selectList(
                Wrappers.lambdaQuery(AdamCaomeiBadge.class)
                        .eq(AdamCaomeiBadge::getDisplayStatus, 1)
                        .orderByAsc(AdamCaomeiBadge::getType)
                        .orderByDesc(AdamCaomeiBadge::getSort)
                        .orderByDesc(AdamCaomeiBadge::getMid)
        );
        log.info("[getPassportHome] 系统已上架的徽章数量, uid: {}, 数量: {}", uid, published.size());

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

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

    private static AdamCaomeiPassportBadgeShelfItemVo toShelfItem(AdamCaomeiBadge b, Map<String, AdamCaomeiPassportUserBadgeDto> claimedMap, boolean isPassportBound, List<String> paidPerformanceIds) {
        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()));
        
        // 判断当前徽章是否已认领
        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(isPassportBound);
            } else if (type == 2) {
                // 演出纪念徽章：只要有对应演出的已支付购票记录，就可认领
                v.setClaimable(paidPerformanceIds != null && paidPerformanceIds.contains(b.getPerformanceId()));
            } 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")
        );
    }
}
