
package com.tmerclub.cloud.order.controller.supplier;


import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.auth.constant.SysTypeEnum;
import com.tmerclub.cloud.api.vo.EsPageVO;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.order.constant.ReturnProcessStatusEnum;
import com.tmerclub.cloud.common.order.dto.OrderRefundSearchDTO;
import com.tmerclub.cloud.common.order.vo.EsOrderRefundVO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.order.constant.RefundApplyType;
import com.tmerclub.cloud.order.constant.RefundStsType;
import com.tmerclub.cloud.order.constant.SupplierHandleStatus;
import com.tmerclub.cloud.order.dto.multishop.OrderRefundDTO;
import com.tmerclub.cloud.order.model.OrderRefundAddr;
import com.tmerclub.cloud.order.model.OrderSettlement;
import com.tmerclub.cloud.order.service.*;
import com.tmerclub.cloud.order.service.*;
import com.tmerclub.cloud.order.vo.OrderRefundAddrVO;
import com.tmerclub.cloud.order.vo.OrderRefundVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.web.bind.annotation.*;

import java.util.Objects;


/**
 * @author tmerclub
 */
@RestController("supplierOrderRefundController")
@RequestMapping("/s/order_refund")
@Tag(name = "供应商端订单退款")
public class OrderRefundController {

    private final Logger LOGGER = LoggerFactory.getLogger(OrderRefundController.class);

    @Autowired
    private OrderRefundService orderRefundService;
    @Autowired
    private OrderRefundAddrService orderRefundAddrService;
    @Autowired
    private RocketMQTemplate orderRefundTemplate;
    @Autowired
    private OrderSettlementService orderSettlementService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private OrderService orderService;

    /**
     * 查看我的退款订单列表
     */
    @GetMapping("/page")
    @Operation(summary = "我的退款订单列表", description = "我的退款订单列表，显示数量")
    public ServerResponseEntity<EsPageVO<EsOrderRefundVO>> list(PageDTO page, OrderRefundSearchDTO orderRefundPageDTO) {
        orderRefundPageDTO.setSupplierId(AuthUserContext.get().getTenantId());
        orderRefundPageDTO.setSysType(AuthUserContext.get().getSysType());
        EsPageVO<EsOrderRefundVO> pageList = orderRefundService.page(page, orderRefundPageDTO);
        return ServerResponseEntity.success(pageList);
    }

    /**
     * 通过id查询
     *
     * @param refundId id
     * @return 查询详细信息
     */
    @GetMapping("/info/{refundId}")
    public ServerResponseEntity<OrderRefundVO> getById(@PathVariable("refundId") Long refundId) {
        OrderRefundVO orderRefund = orderRefundService.getDetailByRefundId(refundId);
        if (!Objects.equals(orderRefund.getSupplierId(), AuthUserContext.get().getTenantId())) {
            return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
        }
        if (Objects.equals(orderRefund.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value()) && orderRefund.getHandelTime() != null) {

            OrderRefundAddr orderRefundAddr = orderRefundAddrService.getByRefundId(refundId);
            orderRefund.setOrderRefundAddr(BeanUtil.map(orderRefundAddr, OrderRefundAddrVO.class));
        }
        if (StrUtil.isNotBlank(orderRefund.getBuyerMobile())) {
            orderRefund.setBuyerMobile(PhoneUtil.hideBetween(orderRefund.getBuyerMobile()).toString());
        }
        return ServerResponseEntity.success(orderRefund);
    }


    /**
     * 进入这个方法，会出现两种情况：
     * 1. 仅退款，此时商家同意买家的退款申请，执行发放退款的操作
     * 2. 退货退款操作:
     * 2.1)退货退款的第一步，商家允许买家退款的申请，商家进行设置退货地址，不执行发放退款的操作
     * 2.2)退货退款的第二步，当商家收到货之后，同意买家退款，此时需要发放退款，但不会执行这个方法，执行的是下面这个方法
     *
     * @see OrderRefundController#returnMoney(OrderRefundDTO)
     */
    @PutMapping("/return_and_refund_audit")
    public ServerResponseEntity<Void> returnAndRefundAudit(@RequestBody OrderRefundDTO orderRefundParam) {
        // 处理退款操作

        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(orderRefundParam.getRefundId());
        if (!Objects.equals(ReturnProcessStatusEnum.APPLY.value(), orderRefundVO.getReturnMoneySts())) {
            // 订单退款状态已发生改变，请勿重复操作
            return ServerResponseEntity.showFailMsg("订单退款状态已发生改变，请勿重复操作");
        }
        if (!Objects.equals(orderRefundVO.getSupplierId(), AuthUserContext.get().getTenantId())) {
            return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
        }
        // 拒绝退款，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            orderRefundVO.setSupplierHandleStatus(SupplierHandleStatus.SUPPLIER_DISAGREE.value());
            orderRefundService.disagreeRefund(orderRefundParam, orderRefundVO);
            return ServerResponseEntity.success();
        }

        // 同意退货，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundVO.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value())) {

            orderRefundService.agreeReturns(orderRefundParam, orderRefundVO, SysTypeEnum.SUPPLIER.value());
            return ServerResponseEntity.success();
        }

        // 同意退款，上面只是同意退货，关系到钱要看下面的
        return agreeRefund(orderRefundParam, orderRefundVO);
    }

    @GetMapping("/is_last_refund")
    @Operation(summary = "是否为最后一单退款")
    public ServerResponseEntity<Boolean> isLastRefund(Long refundId) {
        Long shopId = AuthUserContext.get().getTenantId();
        return ServerResponseEntity.success(orderRefundService.getIsLastRefund(refundId, shopId));
    }


    /**
     * 退货退款的第二步，当商家收到货之后，同意买家退款，此时需要发放退款
     */
    @PutMapping("/return_money")
    public ServerResponseEntity<Void> returnMoney(@Valid @RequestBody OrderRefundDTO orderRefundParam) {

        // 获取退款单信息
        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(orderRefundParam.getRefundId());
        if (!Objects.equals(ReturnProcessStatusEnum.CONSIGNMENT.value(), orderRefundVO.getReturnMoneySts())) {
            throw new LuckException("订单退款状态已发生改变，请勿重复操作");
        }
        if (!Objects.equals(orderRefundVO.getSupplierId(), AuthUserContext.get().getTenantId())) {
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        // 拒绝退款，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            orderRefundVO.setSupplierHandleStatus(SupplierHandleStatus.SUPPLIER_DISAGREE.value());
            orderRefundService.disagreeRefund(orderRefundParam, orderRefundVO);
            return ServerResponseEntity.success();
        }

        return agreeRefund(orderRefundParam, orderRefundVO);
    }


    private ServerResponseEntity<Void> agreeRefund(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVo) {

        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(orderRefundVo.getOrderId());
        if (orderSettlement == null) {
            return ServerResponseEntity.showFailMsg("没有查询到支付记录，无法申请退款");
        }

        orderRefundService.setSupplierOrderRefundInfo(orderRefundVo, orderSettlement);
        // 执行退款，真正意义上的退款，需要确保
        // 发送事务消息
        TransactionSendResult transactionSendResult = orderRefundTemplate.sendMessageInTransaction(RocketMqConstant.ORDER_REFUND_TOPIC, new GenericMessage<>(orderRefundVo), orderRefundParam);

        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            LOGGER.error("退款事务消息发送失败，事务状态：{}", transactionSendResult.getLocalTransactionState());
            return ServerResponseEntity.fail(ResponseEnum.EXCEPTION);
        }
        return ServerResponseEntity.success();
    }
}
