package com.ycwl.basic.pricing.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.common.BaseQueryParameterReq;
import com.ycwl.basic.pricing.dto.CouponClaimRequest;
import com.ycwl.basic.pricing.dto.CouponClaimResult;
import com.ycwl.basic.pricing.dto.req.SceneCouponClaimReq;
import com.ycwl.basic.pricing.dto.req.SceneCouponConfigPageReq;
import com.ycwl.basic.pricing.dto.req.SceneCouponConfigSaveReq;
import com.ycwl.basic.pricing.dto.resp.SceneCouponAvailableResp;
import com.ycwl.basic.pricing.dto.resp.SceneCouponConfigResp;
import com.ycwl.basic.pricing.entity.PriceCouponConfig;
import com.ycwl.basic.pricing.entity.PriceSceneCouponConfig;
import com.ycwl.basic.pricing.mapper.PriceCouponClaimRecordMapper;
import com.ycwl.basic.pricing.mapper.PriceCouponConfigMapper;
import com.ycwl.basic.pricing.mapper.PriceSceneCouponConfigMapper;
import com.ycwl.basic.pricing.service.ICouponService;
import com.ycwl.basic.pricing.service.ISceneCouponService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
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.Objects;

/**
 * 场景优惠券服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SceneCouponServiceImpl implements ISceneCouponService {

    private static final int MAX_PAGE_SIZE = 200;
    private static final Long DEFAULT_SCENIC_ID = 0L;

    private final PriceSceneCouponConfigMapper sceneCouponConfigMapper;
    private final PriceCouponConfigMapper couponConfigMapper;
    private final PriceCouponClaimRecordMapper claimRecordMapper;
    private final ICouponService couponService;

    // ==================== 后台管理接口实现 ====================

    @Override
    public PageInfo<SceneCouponConfigResp> pageConfig(SceneCouponConfigPageReq req) {
        if (req == null) {
            req = new SceneCouponConfigPageReq();
        }
        sanitizePage(req);

        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        List<SceneCouponConfigResp> list = sceneCouponConfigMapper.selectPageWithCouponInfo(
                req.getSceneKey(), req.getScenicId(), req.getCouponId(), req.getEnabled());
        return new PageInfo<>(list);
    }

    @Override
    public SceneCouponConfigResp getConfigDetail(Long id) {
        if (id == null) {
            return null;
        }
        PriceSceneCouponConfig config = sceneCouponConfigMapper.selectById(id);
        if (config == null) {
            return null;
        }

        SceneCouponConfigResp resp = new SceneCouponConfigResp();
        resp.setId(config.getId());
        resp.setSceneKey(config.getSceneKey());
        resp.setCouponId(config.getCouponId());
        resp.setScenicId(config.getScenicId());
        resp.setEnabled(config.getEnabled());
        resp.setSortOrder(config.getSortOrder());
        resp.setCreateTime(config.getCreateTime());
        resp.setUpdateTime(config.getUpdateTime());

        // 填充优惠券信息
        PriceCouponConfig coupon = couponConfigMapper.selectById(config.getCouponId());
        if (coupon != null) {
            resp.setCouponName(coupon.getCouponName());
            resp.setCouponType(coupon.getCouponType() != null ? coupon.getCouponType().name() : null);
            resp.setDiscountValue(coupon.getDiscountValue());
            resp.setCouponActive(coupon.getIsActive());
            resp.setCouponValidFrom(coupon.getValidFrom());
            resp.setCouponValidUntil(coupon.getValidUntil());
        }

        return resp;
    }

    @Override
    public boolean saveConfig(SceneCouponConfigSaveReq req) {
        String err = validateSaveReq(req);
        if (err != null) {
            throw new IllegalArgumentException(err);
        }

        PriceSceneCouponConfig entity = new PriceSceneCouponConfig();
        entity.setSceneKey(req.getSceneKey().trim());
        entity.setCouponId(req.getCouponId());
        entity.setScenicId(req.getScenicId());
        entity.setEnabled(req.getEnabled());
        entity.setSortOrder(Objects.requireNonNullElse(req.getSortOrder(), 0));
        entity.setUpdateTime(new Date());

        try {
            if (req.getId() != null) {
                // 更新
                PriceSceneCouponConfig existing = sceneCouponConfigMapper.selectById(req.getId());
                if (existing == null) {
                    throw new IllegalArgumentException("记录不存在");
                }
                entity.setId(req.getId());
                return sceneCouponConfigMapper.updateById(entity) > 0;
            }

            // 新增前检查唯一性
            PriceSceneCouponConfig existing = sceneCouponConfigMapper.selectOne(
                    new QueryWrapper<PriceSceneCouponConfig>()
                            .eq("scene_key", entity.getSceneKey())
                            .eq("coupon_id", entity.getCouponId())
                            .eq("scenic_id", entity.getScenicId()));
            if (existing != null) {
                // 已存在则更新
                entity.setId(existing.getId());
                return sceneCouponConfigMapper.updateById(entity) > 0;
            }

            entity.setCreateTime(new Date());
            return sceneCouponConfigMapper.insert(entity) > 0;

        } catch (DuplicateKeyException e) {
            throw new IllegalArgumentException("保存失败：配置已存在（sceneKey+couponId+scenicId重复）");
        }
    }

    @Override
    public boolean deleteConfig(Long id) {
        if (id == null) {
            return false;
        }
        return sceneCouponConfigMapper.deleteById(id) > 0;
    }

    @Override
    public List<String> listSceneKeys() {
        return sceneCouponConfigMapper.selectDistinctSceneKeys();
    }

    @Override
    public List<SceneCouponConfigResp> listBySceneKeyAndScenicId(String sceneKey, Long scenicId) {
        return sceneCouponConfigMapper.selectPageWithCouponInfo(sceneKey, scenicId, null, null);
    }

    // ==================== 前端领取接口实现 ====================

    @Override
    public List<SceneCouponAvailableResp> getAvailableCoupons(String sceneKey, Long scenicId, Long userId) {
        if (sceneKey == null || sceneKey.isBlank() || scenicId == null) {
            return new ArrayList<>();
        }

        // 景区隔离查询：先查具体景区，为空则回退到默认配置
        List<SceneCouponConfigResp> configs = getConfigsWithFallback(sceneKey, scenicId);
        if (configs.isEmpty()) {
            return new ArrayList<>();
        }

        List<SceneCouponAvailableResp> result = new ArrayList<>();
        for (SceneCouponConfigResp config : configs) {
            SceneCouponAvailableResp resp = buildAvailableResp(config, userId);
            result.add(resp);
        }

        return result;
    }

    @Override
    @Transactional
    public List<CouponClaimResult> claimCoupons(SceneCouponClaimReq req, Long userId) {
        if (req.getSceneKey() == null || req.getSceneKey().isBlank() || req.getScenicId() == null) {
            return List.of(CouponClaimResult.failure(CouponClaimResult.ERROR_INVALID_PARAMS, "sceneKey和scenicId不能为空"));
        }

        // 获取场景下的优惠券配置
        List<SceneCouponConfigResp> configs = getConfigsWithFallback(req.getSceneKey(), req.getScenicId());
        if (configs.isEmpty()) {
            return List.of(CouponClaimResult.failure("SCENE_NOT_FOUND", "该场景暂无可领取的优惠券"));
        }

        // 如果指定了couponId，只领取指定的
        if (req.getCouponId() != null) {
            configs = configs.stream()
                    .filter(c -> req.getCouponId().equals(c.getCouponId()))
                    .toList();
            if (configs.isEmpty()) {
                return List.of(CouponClaimResult.failure("COUPON_NOT_IN_SCENE", "指定的优惠券不在该场景中"));
            }
        }

        // 调用现有的领取服务
        List<CouponClaimResult> results = new ArrayList<>();
        for (SceneCouponConfigResp config : configs) {
            CouponClaimRequest claimReq = new CouponClaimRequest();
            claimReq.setUserId(userId);
            claimReq.setCouponId(config.getCouponId());
            claimReq.setScenicId(String.valueOf(req.getScenicId()));
            claimReq.setClaimSource("scene:" + req.getSceneKey());

            CouponClaimResult claimResult = couponService.claimCoupon(claimReq);
            results.add(claimResult);
        }

        return results;
    }

    // ==================== 私有方法 ====================

    /**
     * 带景区回退的配置查询
     * 如果景区有配置（哪怕只有一条），则使用景区的配置；
     * 如果景区没有配置，则使用默认景区(scenicId=0)的配置。
     */
    private List<SceneCouponConfigResp> getConfigsWithFallback(String sceneKey, Long scenicId) {
        // 1. 先查具体景区是否有配置
        int count = sceneCouponConfigMapper.countEnabledBySceneKeyAndScenicId(sceneKey, scenicId);
        if (count > 0) {
            // 景区有配置，使用景区的配置
            return sceneCouponConfigMapper.selectEnabledBySceneKeyAndScenicId(sceneKey, scenicId);
        }

        // 2. 景区没有配置，回退到默认配置 (scenicId=0)
        return sceneCouponConfigMapper.selectEnabledBySceneKeyAndScenicId(sceneKey, DEFAULT_SCENIC_ID);
    }

    /**
     * 构建可领取优惠券响应
     */
    private SceneCouponAvailableResp buildAvailableResp(SceneCouponConfigResp config, Long userId) {
        SceneCouponAvailableResp resp = new SceneCouponAvailableResp();

        // 查询优惠券详情
        PriceCouponConfig coupon = couponConfigMapper.selectById(config.getCouponId());
        if (coupon == null) {
            resp.setCouponId(config.getCouponId());
            resp.setCanClaim(false);
            resp.setCannotClaimReason("优惠券不存在");
            return resp;
        }

        resp.setCouponId(coupon.getId());
        resp.setCouponName(coupon.getCouponName());
        resp.setCouponType(coupon.getCouponType() != null ? coupon.getCouponType().name() : null);
        resp.setDiscountValue(coupon.getDiscountValue());
        resp.setMinAmount(coupon.getMinAmount());
        resp.setMaxDiscount(coupon.getMaxDiscount());
        resp.setValidFrom(coupon.getValidFrom());
        resp.setValidUntil(coupon.getValidUntil());
        resp.setUserClaimLimit(coupon.getUserClaimLimit());

        // 查询用户已领取数量
        int userClaimedCount = 0;
        if (userId != null) {
            userClaimedCount = claimRecordMapper.countUserCouponClaims(userId, coupon.getId());
        }
        resp.setUserClaimedCount(userClaimedCount);

        // 计算剩余可领取数量
        int userRemaining;
        if (coupon.getUserClaimLimit() == null || coupon.getUserClaimLimit() <= 0) {
            userRemaining = -1; // -1表示无限制
        } else {
            userRemaining = Math.max(0, coupon.getUserClaimLimit() - userClaimedCount);
        }
        resp.setUserRemaining(userRemaining);

        // 综合判断是否可领取
        String cannotClaimReason = checkCanClaim(coupon, userClaimedCount);
        resp.setCanClaim(cannotClaimReason == null);
        resp.setCannotClaimReason(cannotClaimReason);

        return resp;
    }

    /**
     * 检查是否可领取
     *
     * @return null表示可领取，否则返回不可领取原因
     */
    private String checkCanClaim(PriceCouponConfig coupon, int userClaimedCount) {
        // 1. 检查启用状态
        if (!Boolean.TRUE.equals(coupon.getIsActive())) {
            return "优惠券已停用";
        }

        // 2. 检查有效期
        Date now = new Date();
        if (coupon.getValidFrom() != null && now.before(coupon.getValidFrom())) {
            return "优惠券尚未生效";
        }
        if (coupon.getValidUntil() != null && now.after(coupon.getValidUntil())) {
            return "优惠券已过期";
        }

        // 3. 检查库存
        if (coupon.getTotalQuantity() != null && coupon.getTotalQuantity() > 0) {
            int claimed = coupon.getClaimedQuantity() == null ? 0 : coupon.getClaimedQuantity();
            if (claimed >= coupon.getTotalQuantity()) {
                return "优惠券已领完";
            }
        }

        // 4. 检查用户领取限制
        if (coupon.getUserClaimLimit() != null && coupon.getUserClaimLimit() > 0) {
            if (userClaimedCount >= coupon.getUserClaimLimit()) {
                return "您已达到领取上限";
            }
        }

        return null; // 可领取
    }

    private static void sanitizePage(BaseQueryParameterReq req) {
        if (req.getPageNum() == null || req.getPageNum() < 1) {
            req.setPageNum(1);
        }
        if (req.getPageSize() == null || req.getPageSize() < 1) {
            req.setPageSize(10);
        }
        if (req.getPageSize() > MAX_PAGE_SIZE) {
            req.setPageSize(MAX_PAGE_SIZE);
        }
    }

    private static String validateSaveReq(SceneCouponConfigSaveReq req) {
        if (req == null) {
            return "请求体不能为空";
        }
        if (req.getSceneKey() == null || req.getSceneKey().isBlank()) {
            return "sceneKey不能为空";
        }
        if (req.getCouponId() == null) {
            return "couponId不能为空";
        }
        if (req.getScenicId() == null) {
            return "scenicId不能为空";
        }
        if (req.getEnabled() == null || (req.getEnabled() != 0 && req.getEnabled() != 1)) {
            return "enabled必须为0或1";
        }
        return null;
    }
}
