package com.datacenter.service.impl;

import com.datacenter.job.vo.InviteGrantCandidateVo;
import com.datacenter.mapper.ExperienceGiftInviteGrantMapper;
import com.datacenter.service.ExperienceGiftInviteGrantService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class ExperienceGiftInviteGrantServiceImpl implements ExperienceGiftInviteGrantService {

    private final ExperienceGiftInviteGrantMapper mapper;

    @Resource
    private RestTemplate restTemplate;

    @Value("${admin.host}")
    private String adminHost;

    /**
     * 通过 setter 注入自身代理，使 processGrant 上的 @Transactional 能被 Spring AOP 拦截。
     * @Lazy 避免循环依赖问题。
     */
    @Autowired
    @org.springframework.context.annotation.Lazy
    private ExperienceGiftInviteGrantService self;

    @Override
    public int checkAndGrantInviteGifts() {
        List<InviteGrantCandidateVo> candidates = mapper.findQualifyingCandidates();
        if (candidates.isEmpty()) {
            log.debug("体验金直邀发放：本次无满足条件的仓位");
            return 0;
        }
        log.info("体验金直邀发放：查询到候选仓位 {} 条", candidates.size());

        int granted = 0;
        for (InviteGrantCandidateVo c : candidates) {
            try {
                boolean ok = self.processGrant(c);
                if (ok) {
                    granted++;
                    log.info("体验金直邀发放成功：productId={} inviterId={} memberId={} positionId={} amount={}",
                            c.getProductId(), c.getInviterId(), c.getMemberId(),
                            c.getPositionId(), c.getAmount());
                    notifyGrantEmail(c.getInviterId(), c.getAmount());
                }
            } catch (DuplicateKeyException e) {
                // 去重日志唯一键冲突：并发任务已处理，跳过
                log.warn("体验金直邀发放：仓位 {} 产品 {} 已处理，跳过",
                        c.getPositionId(), c.getProductId());
            } catch (Exception e) {
                log.error("体验金直邀发放异常：positionId={} productId={} inviterId={}",
                        c.getPositionId(), c.getProductId(), c.getInviterId(), e);
            }
        }
        return granted;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean processGrant(InviteGrantCandidateVo c) {
        // ① 事务内二次检查：同一被邀人在同一产品只触发一次（防并发重复处理多个仓位）
        int inviteeTriggerCount = mapper.countGrantedByInviteeAndProduct(c.getMemberId(), c.getProductId());
        if (inviteeTriggerCount > 0) {
            log.debug("体验金直邀发放：被邀人 {} 已触发过产品 {} 的直邀发放，跳过",
                    c.getMemberId(), c.getProductId());
            return false;
        }

        // ② 事务内二次检查 per_user_limit（防并发超发）
        int existingCount = mapper.countGrantedByInviterAndProduct(c.getInviterId(), c.getProductId());
        if (existingCount >= c.getPerUserLimit()) {
            log.debug("体验金直邀发放：邀请人 {} 已达产品 {} 领取上限 {}，跳过",
                    c.getInviterId(), c.getProductId(), c.getPerUserLimit());
            return false;
        }

        // ③ 事务内二次检查 total_quantity（防并发超发）
        if (c.getTotalQuantity() > 0) {
            Integer latestIssued = mapper.getProductIssuedCount(c.getProductId());
            if (latestIssued != null && latestIssued >= c.getTotalQuantity()) {
                log.debug("体验金直邀发放：产品 {} 已达总量上限 {}，跳过",
                        c.getProductId(), c.getTotalQuantity());
                return false;
            }
        }

        Date now = new Date();
        Date expireAt = new Date(now.getTime() + c.getValidityDays() * 24L * 60 * 60 * 1000);

        // ④ 插入体验金发放记录（memberId=邀请人，inviterId=被邀人）
        mapper.insertRecord(
                c.getProductId(),
                c.getProductName(),
                c.getInviterId(),
                c.getMemberId(),
                c.getAmount(),
                c.getMaxProfitPerCard(),
                c.getLeverage(),
                c.getValidityDays(),
                expireAt,
                c.getClientIp(),
                now
        );

        // ⑤ 初始化钱包（INSERT IGNORE）并累加已领取金额
        mapper.initWallet(c.getInviterId());
        mapper.addReceivedToWallet(c.getInviterId(), c.getAmount());

        // ⑥ 产品已发放张数 +1
        mapper.incrementProductIssuedCount(c.getProductId());

        // ⑦ 写入去重日志（UNIQUE KEY 冲突会抛 DuplicateKeyException，触发整体回滚）
        mapper.insertGrantLog(c.getPositionId(), c.getProductId(), c.getInviterId(), now);
        return true;
    }

    private void notifyGrantEmail(Long memberId, BigDecimal amount) {
        try {
            String url = adminHost + "/admin/noauth/experience-gift/grant-email";
            Map<String, Object> body = new HashMap<>();
            body.put("memberId", memberId);
            body.put("amount", amount);
            ResponseEntity<Map> resp = restTemplate.exchange(
                    url, HttpMethod.POST, new HttpEntity<>(body), Map.class);
            log.info("体验金直邀发放邮件通知完成：memberId={} amount={} response={}",
                    memberId, amount, resp.getBody());
        } catch (Exception e) {
            log.warn("体验金直邀发放邮件通知失败：memberId={} amount={}", memberId, amount, e);
        }
    }
}
