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

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopConfig;
import com.czg.account.entity.ShopInfo;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopConfigService;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.config.RabbitPublisher;
import com.czg.constant.MarketConstants;
import com.czg.constants.SystemConstants;
import com.czg.enums.OrderNoPrefixEnum;
import com.czg.exception.CzgException;
import com.czg.market.entity.GbWare;
import com.czg.market.service.GbWareService;
import com.czg.order.dto.CommonRefundDTO;
import com.czg.order.dto.GbOrderQueryParam;
import com.czg.order.dto.GroupJoinDTO;
import com.czg.order.entity.GbOrder;
import com.czg.order.entity.GbOrderDetail;
import com.czg.constants.PayTypeConstants;
import com.czg.order.service.GbOrderDetailService;
import com.czg.order.service.GbOrderService;
import com.czg.order.vo.*;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.order.mapper.GbOrderMapper;
import com.czg.service.order.service.PayService;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgRandomUtils;
import com.czg.utils.FunUtils;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.cache.annotation.CacheEvict;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 拼团订单表 服务层实现。
 *
 * @author ww
 * @since 2025-12-16
 */
@Slf4j
@Service
public class GbOrderServiceImpl extends ServiceImpl<GbOrderMapper, GbOrder> implements GbOrderService {
    @Resource
    private GbWareService wareService;
    @Resource
    private GbOrderDetailService detailService;
    @DubboReference
    private ShopInfoService shopInfoService;
    @DubboReference
    private ShopUserService shopUserService;
    @Resource
    @Lazy
    private PayService payService;
    @Resource
    private RabbitPublisher rabbitPublisher;
    @DubboReference
    private ShopConfigService shopConfigService;

    @CacheEvict(cacheNames = "shopInfo", key = "#shopId")
    @Override
    public boolean upShopConfig(Integer status, Long shopId) {
        ShopConfig shopConfig = new ShopConfig();
        shopConfig.setIsGroupBuy(status);
        boolean update = shopConfigService.update(shopConfig, query().eq(ShopConfig::getId, shopId));
        if (update && status == 0) {
            shopDownRefund(shopId);
            GbWare upWare = new GbWare();
            upWare.setOnlineStatus(SystemConstants.OneZero.ZERO);
            wareService.update(upWare, query().eq(GbWare::getShopId, shopId));
        }
        return update;
    }

    @Override
    public GbOrderCountVO countOrder(GbOrderQueryParam param) {
        return mapper.countOrder(param);
    }

    @Override
    public Page<GbOrderDetailVO> getGbOrderPage(GbOrderQueryParam param) {
        PageHelper.startPage(param.getPage(), param.getSize());
        List<GbOrderDetailVO> result = mapper.getGbOrderPage(param, param.getShopId());
        return PageUtil.convert(new PageInfo<>(result));
    }

    @Override
    public GbOrderDetailVO getGoodsRecordDetail(Long shopId, Long detailId, String groupOrderNo) {
        if (StrUtil.isBlank(groupOrderNo) && detailId == null) {
            throw new CzgException("参数错误");
        }
        GbOrderDetailVO gbOrderDetail;
        if (detailId != null) {
            gbOrderDetail = mapper.getDetailByDetailId(shopId, detailId);
            AssertUtil.isNull(gbOrderDetail, "记录不存在");
        } else {
            gbOrderDetail = mapper.getDetailByGroupNo(shopId, groupOrderNo, StpKit.USER.getLoginIdAsLong());
        }
        if (StrUtil.isNotBlank(groupOrderNo)) {
            gbOrderDetail.setGroupOrderNo(groupOrderNo);
        }
        gbOrderDetail.setShopId(shopId);
        List<GbOrderUserVO> users = mapper.getGbOrderDetailUsers(shopId, gbOrderDetail.getGroupOrderNo());
        gbOrderDetail.setUsers(users);
        return gbOrderDetail;
    }

    @Override
    public GbWareVO getWareDetail(Long shopId, Long wareId, Long userId) {
        GbWareVO ware = wareService.getOneAs(query().eq(GbWare::getId, wareId), GbWareVO.class);
        AssertUtil.isNull(ware, "商品不存在");
        if (ware.getIsDel() || ware.getOnlineStatus() == 0) {
            throw new CzgException("商品已下架");
        }
        ShopInfo shopInfo = shopInfoService.getById(shopId);
        if (shopInfo != null) {
            ware.setShopName(shopInfo.getShopName());
            ware.setShopAddress(shopInfo.getAddress());
        }
        ware.setShopId(shopId);
        List<GbWareOrderVO> orderIngResult = new ArrayList<>();
        List<GbWareOrderVO> orderIng = listAs(query().eq(GbOrder::getWareId, wareId)
                        .eq(GbOrder::getShopId, shopId)
                        .eq(GbOrder::getStatus, "ing")
                        .orderBy(GbOrder::getGroupEndTime).desc()
                , GbWareOrderVO.class);
        for (GbWareOrderVO ing : orderIng) {
            QueryWrapper queryWrapper1 = query();
            queryWrapper1.eq(GbOrderDetail::getIsDel, 0)
                    .and(q -> {
                        q.eq(GbOrderDetail::getStatus, "待成团").or(GbOrderDetail::getStatus).eq("退款中");
                    });
            queryWrapper1.eq(GbOrderDetail::getGroupOrderNo, ing.getGroupOrderNo());
            if (userId != null) {
                queryWrapper1.eq(GbOrderDetail::getUserId, userId);
            }
            boolean exists = detailService.exists(queryWrapper1);
            if (exists) {
                continue;
            }

            QueryWrapper queryWrapper = QueryWrapper.create();
            queryWrapper.eq(GbOrderDetail::getIsDel, 0)
                    .and(q -> {
                        q.eq(GbOrderDetail::getStatus, "待成团").or(GbOrderDetail::getStatus).eq("退款中");
                    });
            queryWrapper.eq(GbOrderDetail::getGroupOrderNo, ing.getGroupOrderNo());
            queryWrapper.orderBy(GbOrderDetail::getPayTime).asc();
            GbOrderDetail detail = detailService.getOne(queryWrapper);
            if (detail != null) {
                ShopUser userInfo = shopUserService.getShopUserInfo(detail.getShopId(), detail.getUserId());
                if (userInfo != null) {
                    ing.setAvatar(userInfo.getHeadImg());
                    ing.setNickName(userInfo.getNickName());
                }
            }
            orderIngResult.add(ing);
        }
        ware.setGbOrderList(orderIngResult);
        return ware;
    }

    @Override
    public CzgResult<Map<String, Object>> groupJoin(GroupJoinDTO param) {
        GbWare ware = wareService.getById(param.getParamId());
        if (ware == null) {
            throw new CzgException("拼团失败，商品不存在");
        }
        if (ware.getOnlineStatus() == 0) {
            throw new CzgException("拼团失败，商品已下架");
        }
        if (ware.getLimitBuyNum() != MarketConstants.Num.NOT_LIMIT && ware.getLimitBuyNum() < param.getNumber()) {
            throw new CzgException("拼团失败，该商品每人限购" + ware.getLimitBuyNum() + "份");
        }
        if (StrUtil.isNotBlank(param.getGroupOrderNo())) {
            GbOrder order = getOne(query().eq(GbOrder::getGroupOrderNo, param.getGroupOrderNo())
                    .eq(GbOrder::getShopId, param.getShopId()));
            if (order == null || !"ing".equals(order.getStatus()) || order.getGroupEndTime().isBefore(LocalDateTime.now())) {
                throw new CzgException("拼团失败，该拼团单不存在或已结束");
            }
        }
        param.setPrice(ware.getGroupPrice().multiply(BigDecimal.valueOf(param.getNumber())));

        GbOrderDetail record = new GbOrderDetail();
        record.setGroupOrderNo(param.getGroupOrderNo());
        record.setShopId(param.getShopId());
        record.setUserId(param.getUserId());
        record.setWareId(param.getParamId());
        record.setCreateTime(LocalDateTime.now());
        record.setNum(param.getNumber());
        record.setPayAmount(param.getPrice());
        record.setStatus("待支付");
        record.setOrderNo(CzgRandomUtils.randomNumber(OrderNoPrefixEnum.GBO, 12, false));
        record.setIsDel(SystemConstants.OneZero.ONE);
        detailService.save(record);
        param.setRecordId(record.getId());
        CzgResult<Map<String, Object>> result = CzgResult.success();
        CzgResult<Map<String, Object>> mapCzgResult = payService.ltPayOther(param, PayTypeConstants.SourceType.WARE, "拼团商品购买");
        if (200 != mapCzgResult.getCode()) {
            return mapCzgResult;
        }
        Map<String, Object> resultMap = new HashMap<>(2);
        resultMap.put("payInfo", mapCzgResult.getData());
        resultMap.put("record", record);
        result.setData(resultMap);
        return result;
    }

    @Override
    public boolean checkout(String verifyCode, Long shopId) {
        GbOrderDetail record = detailService.getOne(query()
                .eq(GbOrderDetail::getIsDel, SystemConstants.OneZero.ZERO)
                .eq(GbOrderDetail::getVerifyCode, verifyCode)
                .eq(GbOrderDetail::getShopId, shopId));
        if (record == null) {
            throw new CzgException("核销失败，核销码不存在");
        }
        if (!"待核销".equals(record.getStatus()) && !"退款中".equals(record.getStatus())) {
            throw new CzgException("核销失败，该商品不可核销");
        }
        boolean success = exists(query().eq(GbOrder::getGroupOrderNo, record.getGroupOrderNo())
                .eq(GbOrder::getShopId, shopId)
                .eq(GbOrder::getStatus, "success"));
        if (!success) {
            throw new CzgException("核销失败，请拼团成功后核销");
        }
        GbOrderDetail upRecord = new GbOrderDetail();
        upRecord.setVerifyTime(LocalDateTime.now());
        upRecord.setStatus("已核销");
        return detailService.update(upRecord, query().eq(GbOrderDetail::getId, record.getId()));
    }

    @Transactional
    @Override
    public void payCallBack(Long recordId, Long payOrderId) {
        GbOrderDetail record = detailService.getById(recordId);
        if (record == null) {
            log.error("积分兑换商品发放失败，记录不存在");
            return;
        }
        record.setIsDel(SystemConstants.OneZero.ZERO);
        record.setStatus("待成团");
        record.setPayOrderId(payOrderId);
        record.setPayTime(LocalDateTime.now());
        record.setVerifyCode(CzgRandomUtils.randomNumber(12, true));
        wareService.upGbWareGroupedNum(record.getWareId(), record.getNum());
        GbWare ware = wareService.getById(record.getWareId());
        if (ware == null) {
            log.error("拼团回调 失败，商品不存在，record:{}", JSONObject.toJSONString(record));
        }
        if (ware != null && StrUtil.isBlank(record.getGroupOrderNo())) {
            GbOrder order = new GbOrder();
            order.setShopId(record.getShopId());
            String groupOrderNo = CzgRandomUtils.randomNumber(OrderNoPrefixEnum.GBO, 12, false);
            order.setGroupOrderNo(groupOrderNo);
            order.setWareId(record.getWareId());
            //(商品名称，商品描述，商品图片，商品详情图片)
            JSONObject wareJson = new JSONObject();
            wareJson.put("wareName", ware.getWareName());
            wareJson.put("wareImgs", ware.getWareImgs());
            wareJson.put("wareDetail", ware.getWareDetail());
            wareJson.put("wareCommentImgs", ware.getWareCommentImgs());
            wareJson.put("limitBuyNum", ware.getLimitBuyNum());
            order.setWareJson(wareJson.toJSONString());
            order.setWareGroupPrice(ware.getGroupPrice());
            order.setWareOriginalPrice(ware.getOriginalPrice());
            order.setGroupPeopleNum(ware.getGroupPeopleNum());
            order.setCurrentPeopleNum(1);
            order.setGroupEndTime(LocalDateTime.now().plusHours(ware.getGroupTimeoutHour()));
            order.setCreateTime(LocalDateTime.now());
            order.setStatus("ing");
            if (ware.getOnlineStatus() == 0 || ware.getIsDel()) {
                order.setStatus("fail");
                order.setGroupEndTime(LocalDateTime.now());
            } else if (ware.getGroupPeopleNum() == 1) {
                order.setStatus("success");
            }
            save(order);
            record.setGroupOrderNo(order.getGroupOrderNo());
            if ("success".equals(order.getStatus())) {
                record.setStatus("待核销");
                //推送 拼团成功
                sendMessage(order.getShopId(), order.getGroupOrderNo());
            }
        } else if(StrUtil.isNotBlank(record.getGroupOrderNo())){
            GbOrder order = getOne(query().eq(GbOrder::getGroupOrderNo, record.getGroupOrderNo())
                    .eq(GbOrder::getShopId, record.getShopId()));
            order.setCurrentPeopleNum(order.getCurrentPeopleNum() + 1);
            if (ware == null || ware.getOnlineStatus() == 0 || ware.getIsDel()) {
                order.setStatus("fail");
                order.setGroupEndTime(LocalDateTime.now());
            } else if (order.getCurrentPeopleNum().equals(order.getGroupPeopleNum())) {
                order.setStatus("success");
                order.setGroupEndTime(LocalDateTime.now());
                record.setStatus("待核销");
                GbOrderDetail upRecord = new GbOrderDetail();
                upRecord.setStatus("待核销");
                detailService.update(upRecord, query()
                        .eq(GbOrderDetail::getGroupOrderNo, order.getGroupOrderNo())
                        .eq(GbOrderDetail::getShopId, order.getShopId())
                        .eq(GbOrderDetail::getIsDel, SystemConstants.OneZero.ZERO)
                        .eq(GbOrderDetail::getStatus, "待成团")
                );
                //推送 拼团成功
                sendMessage(order.getShopId(), order.getGroupOrderNo());
            }
            updateById(order);
        }
        detailService.updateById(record);
        if (ware == null || ware.getOnlineStatus() == 0 || ware.getIsDel()) {
            refundByGbOrderDetail(record, true, "商品已下架 自动退款。");
        }
    }

    @Override
    public boolean applyRefund(CommonRefundDTO param, Long userId) {
        GbOrderDetail record = detailService.getOne(query()
                .eq(GbOrderDetail::getIsDel, SystemConstants.OneZero.ZERO)
                .eq(GbOrderDetail::getId, param.getRecordId())
                .eq(GbOrderDetail::getUserId, userId));
        AssertUtil.isNull(record, "记录不存在");
        if (!"待成团".equals(record.getStatus()) && !"待核销".equals(record.getStatus())) {
            throw new CzgException("申请失败，该商品不可申请退款");
        }
        if ("待成团".equals(record.getStatus())) {
            return refundByGbOrderDetail(record, false, param.getReason());
        }
        GbOrderDetail upRecord = new GbOrderDetail();
        upRecord.setStatus("退款中");
        upRecord.setCancelReason(param.getReason());
        upRecord.setCancelTime(LocalDateTime.now());

        return detailService.update(upRecord, QueryWrapper.create()
                .eq(GbOrderDetail::getId, param.getRecordId())
                .eq(GbOrderDetail::getOrderNo, record.getOrderNo())
                .eq(GbOrderDetail::getUserId, userId)
                .eq(GbOrderDetail::getShopId, record.getShopId())
        );
    }

    @Override
    public boolean cancelRefund(CommonRefundDTO param, Long userId, Long shopId) {
        GbOrderDetail record = detailService.getOne(query()
                .eq(GbOrderDetail::getId, param.getRecordId())
                .eq(GbOrderDetail::getIsDel, SystemConstants.OneZero.ZERO)
                .eq(GbOrderDetail::getUserId, userId));
        AssertUtil.isNull(record, "取消失败，订单不存在");
        if (!"退款中".equals(record.getStatus())) {
            throw new CzgException("取消失败，订单不处于退款中");
        }
        boolean success = exists(query().eq(GbOrder::getGroupOrderNo, record.getGroupOrderNo())
                .eq(GbOrder::getShopId, shopId)
                .eq(GbOrder::getStatus, "success"));
        GbOrderDetail upRecord = new GbOrderDetail();
        if (success) {
            upRecord.setStatus("待核销");
        } else {
            upRecord.setStatus("待成团");
        }

        if (record.getVerifyTime() != null) {
            upRecord.setStatus("已核销");
        }

        upRecord.setCancelReason(param.getReason());
        upRecord.setCancelTime(LocalDateTime.now());

        return detailService.update(upRecord, QueryWrapper.create()
                .eq(GbOrderDetail::getId, param.getRecordId())
                .eq(GbOrderDetail::getOrderNo, param.getOrderNo())
                .eq(GbOrderDetail::getUserId, userId)
                .eq(GbOrderDetail::getShopId, shopId)
        );
    }

    @Transactional
    @Override
    public boolean agreeRefund(CommonRefundDTO param, Long shopId) {
        GbOrderDetail record = detailService.getOne(QueryWrapper.create()
                .eq(GbOrderDetail::getIsDel, SystemConstants.OneZero.ZERO)
                .eq(GbOrderDetail::getId, param.getRecordId())
                .eq(GbOrderDetail::getShopId, shopId));
        AssertUtil.isNull(record, "退款失败，订单不存在");
        //待支付/待核销/待成团/已核销/退款中/已退款
        if (!"待核销".equals(record.getStatus()) && !"待成团".equals(record.getStatus()) && !"退款中".equals(record.getStatus())) {
            throw new CzgException("退款失败，订单不处于待退款");
        }
        return refundByGbOrderDetail(record, false, param.getReason());
    }

    @Override
    public boolean editGbWareOnlineStatus(Long id, Integer onlineStatus) {
        GbWare gbWare = new GbWare();
        gbWare.setOnlineStatus(onlineStatus);
        boolean update = wareService.update(gbWare, query().eq(GbWare::getId, id).eq(GbWare::getShopId, StpKit.USER.getShopId()));
        if (update && onlineStatus == 0) {
            //退钱
            wareDownRefund(id);
        }
        return update;
    }

    @Override
    public boolean expireRefund(Long gbOrderId, GbOrder order) {
        if (gbOrderId == null && order == null) {
            return false;
        }
        if (order == null) {
            order = getOne(query().eq(GbOrder::getId, gbOrderId).eq(GbOrder::getStatus, "ing"));
        }
        if (order == null) {
            return false;
        }
        return refundByGbOrder(order, "成团期限超时");
    }

    @Override
    public boolean wareDownRefund(Long wareId) {
        List<GbOrder> list = list(query().eq(GbOrder::getWareId, wareId).eq(GbOrder::getStatus, "ing"));
        for (GbOrder gbOrder : list) {
            refundByGbOrder(gbOrder, "所属活动变更为下架状态");
        }
        return true;
    }

    @Override
    public boolean shopDownRefund(Long shopId) {
        List<GbOrder> list = list(query().eq(GbOrder::getShopId, shopId).eq(GbOrder::getStatus, "ing"));
        for (GbOrder gbOrder : list) {
            refundByGbOrder(gbOrder, "商品拼团功能关闭");
        }
        return true;
    }

    //单个退
    public boolean refundByGbOrderDetail(GbOrderDetail record, boolean isAuto, String reason) {
        //回退 人数
        GbOrder gbOrder = getOne(query().eq(GbOrder::getGroupOrderNo, record.getGroupOrderNo()).eq(GbOrder::getShopId, record.getShopId()));
        if (gbOrder != null) {
            GbOrder upOrder = new GbOrder();
            upOrder.setId(gbOrder.getId());
            upOrder.setCurrentPeopleNum(gbOrder.getCurrentPeopleNum() - 1);
            if (upOrder.getCurrentPeopleNum() == 0) {
                upOrder.setStatus("fail");
                upOrder.setGroupEndTime(LocalDateTime.now());
            }
            updateById(upOrder);
        }
        FunUtils.safeRunVoid(() -> refundAmount(record, isAuto, reason), "订单详情{}退款失败", record.getId());
        return false;
    }

    //大量退
    public boolean refundByGbOrder(GbOrder gbOrder, String reason) {
        if (gbOrder == null) {
            return false;
        }
        List<GbOrderDetail> details = detailService.list(query()
                .eq(GbOrderDetail::getShopId, gbOrder.getShopId())
                .eq(GbOrderDetail::getGroupOrderNo, gbOrder.getGroupOrderNo())
                .ne(GbOrderDetail::getStatus, "已退款")
                .eq(GbOrderDetail::getIsDel, SystemConstants.OneZero.ZERO));
        details.forEach(item -> FunUtils.safeRunVoid(() -> refundAmount(item, true, reason), "订单详情{}退款失败", item.getId()));
        GbOrder upOrder = new GbOrder();
        upOrder.setStatus("fail");
        update(upOrder, query().eq(GbOrder::getId, gbOrder.getId()));
        return true;
    }


    /**
     * @param isAuto 是否自动退款
     */
    private boolean refundAmount(GbOrderDetail record, boolean isAuto, String reason) {
        //退钱
        String refPayOrderNo = CzgRandomUtils.snowflake(OrderNoPrefixEnum.REP);
        payService.unifyRefund(record.getShopId(), record.getId(), record.getPayOrderId(), refPayOrderNo,
                StrUtil.isBlankIfStr(reason) ? "拼团退款" : reason, record.getPayAmount());
        GbOrderDetail upRecord = new GbOrderDetail();
        upRecord.setStatus("已退款");
        if (isAuto) {
            upRecord.setRefundMark("(成团失败)");
        }
        upRecord.setCancelReason(reason);
        return detailService.update(upRecord, query().eq(GbOrderDetail::getId, record.getId()));
    }

    //推送 拼团成功 消息
    private void sendMessage(Long shopId, String groupOrderNo) {
        rabbitPublisher.sendApplySmsMsg(shopId + "," + groupOrderNo, "groupBuyYes");
    }
}
