package com.czg.service.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopUserService;
import com.czg.enums.OrderNoPrefixEnum;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkShopCouponGiftDTO;
import com.czg.market.entity.MkPointsGoods;
import com.czg.market.entity.MkPointsGoodsRecord;
import com.czg.market.entity.MkPointsUser;
import com.czg.market.entity.ShopCoupon;
import com.czg.market.enums.PointsConstant;
import com.czg.market.service.*;
import com.czg.order.dto.CommonRefundDTO;
import com.czg.order.dto.LtPayOtherDTO;
import com.czg.constants.PayTypeConstants;
import com.czg.order.service.PointsGoodPayService;
import com.czg.resp.CzgResult;
import com.czg.service.order.service.PayService;
import com.czg.utils.CzgRandomUtils;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ww
 */
@Slf4j
@Service
public class PointsGoodPayServiceImpl implements PointsGoodPayService {
    @Resource
    private ShopUserService shopUserService;
    @Resource
    private MkPointsUserService pointsUserService;
    @Resource
    private MkPointsGoodsService goodsService;
    @Resource
    private MkPointsGoodsRecordService goodsRecordService;
    @Resource
    private ShopCouponService shopCouponService;
    @Resource
    private MkShopCouponRecordService couponRecordService;
    @Resource
    @Lazy
    private PayService payService;

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> exchange(LtPayOtherDTO param) {
        MkPointsGoods goods = goodsService.getById(param.getParamId());
        if (goods == null) {
            throw new CzgException("兑换失败，商品不存在");
        }
        if (goods.getStatus() != 1) {
            throw new CzgException("兑换失败，商品已下架");
        }
        if (goods.getQuantity() <= 0) {
            throw new CzgException("兑换失败，商品库存不足");
        }
        Integer boughtCount = goodsRecordService.getOneAs(QueryWrapper.create().select("sum(number)")
                .eq(MkPointsGoodsRecord::getPointsGoodsId, param.getParamId())
                .ne(MkPointsGoodsRecord::getStatus, "已退款")
                .eq(MkPointsGoodsRecord::getUserId, param.getUserId()), Integer.class);
        if (goods.getLimitQuota() != null && goods.getLimitQuota() > 0 && boughtCount != null && boughtCount >= goods.getLimitQuota()) {
            throw new CzgException("兑换失败，该商品每人限制兑换" + goods.getLimitQuota() + "件");
        }
        MkPointsUser pointsUser = pointsUserService.getPointsUser(param.getShopId(), null, param.getUserId());
        if (pointsUser == null) {
            throw new CzgException("兑换失败，用户积分不足");
        }
        if (goods.getRequiredPoints() > 0 && pointsUser.getPointBalance() < (long) goods.getRequiredPoints() * param.getNumber()) {
            throw new CzgException("兑换失败，积分不足");
        }
        ShopUser shopUser = shopUserService.getUserInfo(param.getShopId(), param.getUserId());
        if (shopUser == null) {
            throw new CzgException("兑换失败，店铺用户不存在");
        }

        MkPointsGoodsRecord record = new MkPointsGoodsRecord();
        record.setOrderNo(CzgRandomUtils.randomNumber(OrderNoPrefixEnum.DH, 20, true));
        record.setShopId(param.getShopId());
        record.setPointsGoodsId(param.getParamId());
        record.setPointsGoodsName(goods.getGoodsName());
        record.setGoodsImageUrl(goods.getGoodsImageUrl());
        record.setGoodsCategory(goods.getGoodsCategory());
        record.setReceiveType(goods.getReceiveType());
        record.setShopUserId(shopUser.getId());
        record.setUserId(param.getUserId());
        record.setNumber(param.getNumber());
        record.setSpendPoints(goods.getRequiredPoints() * param.getNumber());
        record.setExtraPaymentAmount(goods.getExtraPrice() != null ? goods.getExtraPrice().multiply(new BigDecimal(param.getNumber())) : BigDecimal.ZERO);
        record.setCreateTime(LocalDateTime.now());
        if (goods.getExtraPrice() != null && goods.getExtraPrice().compareTo(BigDecimal.ZERO) > 0) {
            param.checkPayInfo();
            param.setPrice(record.getExtraPaymentAmount());
            record.setStatus("待支付");
            record.setIsDel(1);
            goodsRecordService.save(record);
            param.setRecordId(record.getId());
            CzgResult<Map<String, Object>> result = CzgResult.success();
            CzgResult<Map<String, Object>> mapCzgResult = payService.ltPayOther(param, PayTypeConstants.SourceType.POINT, "积分商品购买");
            if (200 != mapCzgResult.getCode()) {
                return mapCzgResult;
            }
            Map<String, Object> resultMap = new HashMap<>(2);
            resultMap.put("payInfo", mapCzgResult.getData());
            resultMap.put("goodsRecord", record);
            result.setData(resultMap);
            return result;
        }

        //正常处理
        exchangeAfter(record, goods);
        return CzgResult.success(BeanUtil.beanToMap(record));
    }

    @Override
    public boolean applyRefund(CommonRefundDTO param, Long userId) {
        MkPointsGoodsRecord record = new MkPointsGoodsRecord();
        record.setStatus("退款中");
        record.setCancelOrRefundReason(param.getReason());
        record.setCancelOrRefundTime(LocalDateTime.now());

        return goodsRecordService.update(record, QueryWrapper.create()
                .eq(MkPointsGoodsRecord::getId, param.getRecordId())
                .eq(MkPointsGoodsRecord::getOrderNo, param.getOrderNo())
                .eq(MkPointsGoodsRecord::getUserId, userId)
        );
    }

    @Override
    public boolean cancelRefund(CommonRefundDTO param, Long userId, Long shopId) {
        MkPointsGoodsRecord record1 = goodsRecordService.getById(param.getRecordId());
        if (record1 == null) {
            throw new CzgException("取消失败，订单不存在");
        }
        if (!"退款中".equals(record1.getStatus())) {
            throw new CzgException("取消失败，订单不处于退款中");
        }
        MkPointsGoodsRecord record = new MkPointsGoodsRecord();
        if (record1.getCheckoutTime() != null) {
            record.setStatus("已完成");
        } else {
            record.setStatus("待核销");
        }
        record.setCancelOrRefundReason(param.getReason());
        record.setCancelOrRefundTime(LocalDateTime.now());

        return goodsRecordService.update(record, QueryWrapper.create()
                .eq(MkPointsGoodsRecord::getId, param.getRecordId())
                .eq(MkPointsGoodsRecord::getOrderNo, param.getOrderNo())
                .eq(MkPointsGoodsRecord::getUserId, userId)
                .eq(MkPointsGoodsRecord::getShopId, shopId)
        );
    }

    @Override
    @Transactional
    public boolean agreeRefund(CommonRefundDTO param, Long shopId) {
        MkPointsGoodsRecord record = goodsRecordService.getOne(QueryWrapper.create()
                .eq(MkPointsGoodsRecord::getId, param.getRecordId())
                .eq(MkPointsGoodsRecord::getShopId, shopId)
                .eq(MkPointsGoodsRecord::getIsDel, 0));
        if (record == null) {
            throw new CzgException("操作失败，记录不存在");
        }
        if (!"待核销".equals(record.getStatus()) && !"退款中".equals(record.getStatus())) {
            throw new CzgException("退款失败，订单不处于待退款");
        }
        //退积分
        if (record.getSpendPoints() != null && record.getSpendPoints() > 0) {
            //回增积分
            pointsUserService.alterPoints(record.getUserId(), record.getShopUserId(), record.getShopId(), PointsConstant.ADD,
                    record.getSpendPoints(), record.getId(), "积分商品兑换退款");
        }
        //退钱
        if (record.getExtraPaymentAmount() != null && record.getExtraPaymentAmount().compareTo(BigDecimal.ZERO) > 0) {
            String refPayOrderNo = CzgRandomUtils.snowflake(OrderNoPrefixEnum.REP);
            payService.unifyRefund(shopId, record.getId(), record.getPayOrderId(), refPayOrderNo,
                    StrUtil.isBlankIfStr(param.getReason()) ? "积分商品退款" : param.getReason(), record.getExtraPaymentAmount());
        }
        //回退 库存
        MkPointsGoods goods = goodsService.getById(record.getPointsGoodsId());
        if (goods != null) {
            goodsService.upNumberById(goods.getId(), goods.getQuantity() + record.getNumber(), null);
        }
        MkPointsGoodsRecord upRecord = new MkPointsGoodsRecord();
        upRecord.setId(record.getId());
        upRecord.setStatus("已退款");
        upRecord.setCancelOrRefundReason(param.getReason());
        upRecord.setCancelOrRefundTime(LocalDateTime.now());
        return goodsRecordService.updateById(upRecord);
    }

    @Override
    @Transactional
    public void payCallBack(Long recordId, Long payOrderId) {
        MkPointsGoodsRecord record = goodsRecordService.getById(recordId);
        if (record == null) {
            log.error("积分兑换商品发放失败，记录不存在");
            return;
        }
        record.setPayOrderId(payOrderId);
        record.setPayTime(LocalDateTime.now());
        exchangeAfter(record, null);
    }


    private MkPointsGoodsRecord exchangeAfter(MkPointsGoodsRecord record, MkPointsGoods goods) {
        if (goods == null) {
            goods = goodsService.getById(record.getPointsGoodsId());
        }
        record.setIsDel(0);
        if ("优惠券".equals(goods.getGoodsCategory())) {
            ShopCoupon coupon = shopCouponService.getById(goods.getCouponId());
            if (coupon != null) {
                record.setCouponJson(JSONObject.toJSONString(coupon));
                record.fillCouponInfo();
            }
            record.setStatus("已完成");
            record.setCheckoutTime(LocalDateTime.now());
            goodsRecordService.saveOrUpdate(record);
            MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO()
                    .setCouponId(goods.getCouponId())
                    .setShopId(record.getShopId())
                    .setSourceId(record.getId())
                    .setShopUserId(record.getShopUserId())
                    .setSource("积分兑换");
            couponRecordService.receiveCoupon(giftDTO, record.getNumber(), false);
            goodsService.upNumberById(goods.getId(), goods.getQuantity() - record.getNumber(), goods.getTotalExchangeCount() + record.getNumber());
            //扣除积分
            pointsUserService.alterPoints(record.getUserId(), null, record.getShopId(), PointsConstant.SUB,
                    record.getSpendPoints(), record.getId(), "积分商品兑换");
            return record;
        } else {
            record.setStatus("待核销");
            record.setCouponCode(CzgRandomUtils.randomNumber(12, true));
            goodsRecordService.saveOrUpdate(record);
            goodsService.upNumberById(goods.getId(), goods.getQuantity() - record.getNumber(), goods.getTotalExchangeCount() + record.getNumber());
            //扣除积分
            pointsUserService.alterPoints(record.getUserId(), null, record.getShopId(), PointsConstant.SUB,
                    record.getSpendPoints(), record.getId(), "积分商品兑换");
        }
        return record;
    }
}
