package com.bonus.canteen.core.order.domain;

import cn.hutool.core.collection.CollUtil;
import com.bonus.canteen.core.order.constants.*;
import com.bonus.canteen.core.order.domain.param.*;
import com.bonus.canteen.core.pay.constants.PayChannelEnum;
import com.bonus.canteen.core.pay.constants.PayStateEnum;
import com.bonus.common.core.annotation.Excel;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.web.domain.BaseEntity;
import com.bonus.common.security.utils.SecurityUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 订单对象 order_info
 * 
 * @author ruoyi
 * @date 2025-04-14
 */

@Data
public class OrderInfo extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 订单号 */
    private Long orderId;

    /** 设备订单号 */
    @Excel(name = "设备订单号")
    private String deviceOrderId;

    /** 设备sn */
    @Excel(name = "设备sn")
    private String deviceSn;

    /** 设备编号 */
    @Excel(name = "设备编号")
    private String deviceNum;

    /** 人员编号 */
    @Excel(name = "人员编号")
    private Long userId;

    /** 身份验证方式 1 刷卡 2 刷脸 3 扫码 */
    @Excel(name = "身份验证方式 1 刷卡 2 刷脸 3 扫码")
    private Integer identityVerification;

    /** 订单来源类型 */
    @Excel(name = "订单来源类型")
    private Integer sourceType;

    /** 是否在线订单 1 是 2 否 */
    @Excel(name = "是否在线订单 1 是 2 否")
    private Integer isOnline;

    /** 食堂id */
    @Excel(name = "食堂id")
    private Long canteenId;

    /** 食堂名称 */
    @Excel(name = "食堂名称")
    private String canteenName;

    /** 档口id */
    @Excel(name = "档口id")
    private Long stallId;

    /** 档口名称 */
    @Excel(name = "档口名称")
    private String stallName;

    /** 餐次类型 1-早餐 2-午餐 3-晚餐 4-下午茶 5-夜宵 */
    @Excel(name = "餐次类型 1-早餐 2-午餐 3-晚餐 4-下午茶 5-夜宵")
    private Integer mealtimeType;

    /** 餐次名称 */
    @Excel(name = "餐次名称")
    private String mealtimeName;

    /** 订单日期 yyyy-MM-dd */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    @Excel(name = "订单日期 yyyy-MM-dd", width = 30, dateFormat = "yyyy-MM-dd")
    private Date orderDate;

    /** 应付金额  分 */
    @Excel(name = "应付金额  分")
    private BigDecimal payableAmount;

    /** 优惠金额 分 */
    @Excel(name = "优惠金额 分")
    private BigDecimal discountsAmount;

    /** 实付金额 分 */
    @Excel(name = "实付金额 分")
    private BigDecimal realAmount;

    /** 账户支付金额 分 */
    @Excel(name = "账户支付金额 分")
    private BigDecimal accountPayAmount;

    /** 外部支付金额 分（除账户外） */
    @Excel(name = "外部支付金额 分", readConverterExp = "除=账户外")
    private BigDecimal externalPayAmount;

    /** 累计退款金额 分 */
    @Excel(name = "累计退款金额 分")
    private BigDecimal refundAmount;

    /** 下单时间 yyyy-MM-dd HH:mm:ss */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Excel(name = "下单时间 yyyy-MM-dd HH:mm:ss", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
    private Date orderTime;

    /** 订单类型 1 当餐 2 预订餐 3 报餐 4 商城  11 线下消费 12 自助餐 21 补扣 22 外部订单 */
    @Excel(name = "订单类型 1 当餐 2 预订餐 3 报餐 4 商城  11 线下消费 12 自助餐 21 补扣 22 外部订单")
    private Integer orderType;

    /** 订单状态 1 已下单 2 已完成 3 已取消 */
    @Excel(name = "订单状态 1 已下单 2 已完成 3 已取消")
    private Integer orderState;

    /** 订单退款状态 1 未退单 2 已退单 3 部分退单 */
    @Excel(name = "订单退款状态 1 未退单 2 已退单 3 部分退单")
    private Integer orderRefundState;

    /** 扣款类型 1 下单扣款 2 核销扣款 */
    @Excel(name = "扣款类型 1 下单扣款 2 核销扣款")
    private Integer deductionType;

    /** 支付时间 yyyy-MM-dd HH:mm:ss */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Excel(name = "支付时间 yyyy-MM-dd HH:mm:ss", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
    private Date payTime;

    /** 支付方式 */
    @Excel(name = "支付方式")
    private Integer payType;

    /** 支付渠道 */
    @Excel(name = "支付渠道")
    private Integer payChannel;

    /** 支付状态 1 待支付 2 支付中 3 支付成功 4 支付失败 5 支付取消 6 部分支付 */
    @Excel(name = "支付状态 1 待支付 2 支付中 3 支付成功 4 支付失败 5 支付取消 6 部分支付")
    private Integer payState;

    /** 支付参数  刷卡:卡号  扫码:二维码 */
    @Excel(name = "支付参数  刷卡:卡号  扫码:二维码")
    private String payParam;

    /** 配送费 分 */
    @Excel(name = "配送费 分")
    private BigDecimal deliveryAmount;

    /** 包装费 分 */
    @Excel(name = "包装费 分")
    private BigDecimal packingAmount;

    /** 配送方式 */
    @Excel(name = "配送方式")
    private Integer deliveryType;

    /** 评论状态 1 已评论 2 未评论 */
    @Excel(name = "评论状态 1 已评论 2 未评论")
    private Integer commentState;

    private String deviceName;

    private String nickName;

    private String phoneNumber;

    private String deptFullName;

    private String areaName;

    List<OrderDetail> orderDetailList;

    public List<OrderInfo> of(OrderAddParam param) {
        List<OrderInfo> orderInfoList = new ArrayList<>();
        List<OrderInfoAddParam> orderList = param.getOrderList();
        if(CollUtil.isNotEmpty(orderList)) {
            for(OrderInfoAddParam orderInfoAddParam : orderList) {
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setDeviceOrderId(StringUtils.defaultString(orderInfoAddParam.getDeviceOrderId(), StringUtils.EMPTY));
                orderInfo.setDeviceSn(StringUtils.defaultString(orderInfoAddParam.getDeviceSn(), StringUtils.EMPTY));
                orderInfo.setDeviceNum(StringUtils.defaultString(orderInfoAddParam.getDeviceNum(), StringUtils.EMPTY));
                orderInfo.setUserId(param.getUserId());
                orderInfo.setSourceType(param.getSourceType());
                orderInfo.setCreateBy(SecurityUtils.getUsername());
                orderInfo.setCreateTime(DateUtils.getNowDate());
                orderInfo.setUpdateBy(SecurityUtils.getUsername());
                orderInfo.setUpdateTime(DateUtils.getNowDate());
                orderInfo.setPayType(param.getPayType());
                Long canteenId = orderInfoAddParam.getCanteenId();
                orderInfo.setCanteenId(Objects.isNull(canteenId) ? -1 : canteenId);
                Long stallId = orderInfoAddParam.getStallId();
                orderInfo.setStallId(Objects.isNull(stallId) ? -1 : stallId);
                orderInfo.setOrderDate(orderInfoAddParam.getOrderDate());
                orderInfo.setOrderType(orderInfoAddParam.getOrderType());
                Integer mealtimeType = orderInfoAddParam.getMealtimeType();
                orderInfo.setMealtimeType(Objects.isNull(mealtimeType) ? -1 : mealtimeType);
                orderInfo.setMealtimeName(orderInfoAddParam.getMealtimeName());
                orderInfo.setIsOnline(Objects.isNull(param.getIsOnline()) ? 1 : param.getIsOnline());
                orderInfo.setOrderState(OrderStateEnum.WAIT_PLACE.getKey());
                orderInfo.setOrderRefundState(OrderRefundStateEnum.UN_REFUND.getKey());
                orderInfo.setDeductionType(DeductionTypeEnum.PAY_PLACE.getKey());
                orderInfo.setPayChannel(PayChannelEnum.ACC.getKey());
                orderInfo.setPayState(PayStateEnum.PAY_INPROCESS.getKey());
                orderInfo.setDeliveryAmount(BigDecimal.ZERO);
                orderInfo.setPackingAmount(BigDecimal.ZERO);
                orderInfo.setDeliveryType(DeliveryTypeEnum.SELF_TAKE.getKey());
                orderInfo.setCommentState(CommentStateEnum.UN_COMMENT.getKey());
                orderInfo.setOrderTime(DateUtils.getNowDate());
                orderInfo.setPayableAmount(BigDecimal.ZERO);
                orderInfo.setDiscountsAmount(BigDecimal.ZERO);
                orderInfo.setRealAmount(BigDecimal.ZERO);
                orderInfo.setExternalPayAmount(BigDecimal.ZERO);
                orderInfo.setRefundAmount(BigDecimal.ZERO);
                List<OrderDetailInfoAddParam> orderDetailInfoAddParams =orderInfoAddParam.getOrderDetailList();
                if(CollUtil.isNotEmpty(orderDetailInfoAddParams)) {
                    List<OrderDetail> orderDetailList = CollUtil.newArrayList();
                    for(OrderDetailInfoAddParam orderDetailInfoAddParam : orderDetailInfoAddParams) {
                        OrderDetail orderDetail = getOrderDetail(orderDetailInfoAddParam, orderInfo);
                        orderDetailList.add(orderDetail);
                        BigDecimal saleTotalAmount = orderDetail.getSalePrice().multiply(new BigDecimal(orderDetail.getQuantity()));
                        BigDecimal discountTotalAmount = orderDetail.getDiscountPrice().multiply(new BigDecimal(orderDetail.getQuantity()));
                        orderInfo.setPayableAmount(orderInfo.getPayableAmount().add(saleTotalAmount));
                        orderInfo.setDiscountsAmount(orderInfo.getDiscountsAmount().add(discountTotalAmount));
                        orderInfo.setRealAmount(orderInfo.getRealAmount().add(orderDetail.getTotalAmount()));
                        orderInfo.setAccountPayAmount(orderInfo.getRealAmount());
                    }
                    orderInfo.setOrderDetailList(orderDetailList);
                }
                orderInfoList.add(orderInfo);
            }
        }
        return orderInfoList;
    }

    private OrderDetail getOrderDetail(OrderDetailInfoAddParam orderDetailInfoAddParam, OrderInfo orderInfo) {
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderDate(orderInfo.getOrderDate());
        orderDetail.setGoodsId(orderDetailInfoAddParam.getGoodsId());
        orderDetail.setGoodsName(orderDetailInfoAddParam.getGoodsName());
        orderDetail.setGoodsImgUrl(orderDetailInfoAddParam.getGoodsImgUrl());
        orderDetail.setRecipeDetailId(orderDetailInfoAddParam.getRecipeDetailId());
        orderDetail.setSalePrice(orderDetailInfoAddParam.getSalePrice());
        orderDetail.setDiscountPrice(orderDetailInfoAddParam.getDiscountPrice());
        orderDetail.setFinalPrice(orderDetailInfoAddParam.getFinalPrice());
        orderDetail.setQuantity(orderDetailInfoAddParam.getQuantity());
        orderDetail.setSalesMode(orderDetailInfoAddParam.getSalesMode());
        orderDetail.setDetailType(orderDetailInfoAddParam.getDetailType());
        BigDecimal totalAmount = orderDetail.getFinalPrice().multiply(new BigDecimal(orderDetail.getQuantity()));
        orderDetail.setTotalAmount(totalAmount);
        orderDetail.setCalcTotalAmount(totalAmount);
        orderDetail.setRealAmount(totalAmount);
        orderDetail.setDetailState(OrderDetailStateEnum.NORMAL.getKey());
        orderDetail.setRefundAmount(BigDecimal.ZERO);
        orderDetail.setRefundNum(0);
        orderDetail.setDeviceSn(StringUtils.defaultString(orderInfo.getDeviceSn(), StringUtils.EMPTY));
        orderDetail.setSerialNum(StringUtils.EMPTY);
        orderDetail.setCreateBy(SecurityUtils.getUsername());
        orderDetail.setCreateTime(DateUtils.getNowDate());
        orderDetail.setUpdateBy(SecurityUtils.getUsername());
        orderDetail.setUpdateTime(DateUtils.getNowDate());
        return orderDetail;
    }

    public List<OrderInfo> of(DeviceOrderAddParam param) {
        List<OrderInfo> orderInfoList = new ArrayList<>();
        List<DeviceOrderInfoAddParam> orderList = param.getOrderList();
        if(CollUtil.isNotEmpty(orderList)) {
            for(DeviceOrderInfoAddParam orderInfoAddParam : orderList) {
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setDeviceOrderId(StringUtils.defaultString(orderInfoAddParam.getDeviceOrderId(), StringUtils.EMPTY));
                orderInfo.setDeviceSn(StringUtils.defaultString(orderInfoAddParam.getDeviceSn(), StringUtils.EMPTY));
                orderInfo.setDeviceNum(StringUtils.defaultString(orderInfoAddParam.getDeviceNum(), StringUtils.EMPTY));
                orderInfo.setIdentityVerification(orderInfoAddParam.getIdentityVerification());
                orderInfo.setUserId(param.getUserId());
                orderInfo.setSourceType(param.getSourceType());
                orderInfo.setCreateBy(SecurityUtils.getUsername());
                orderInfo.setCreateTime(DateUtils.getNowDate());
                orderInfo.setUpdateBy(SecurityUtils.getUsername());
                orderInfo.setUpdateTime(DateUtils.getNowDate());
                Long canteenId = orderInfoAddParam.getCanteenId();
                orderInfo.setCanteenId(Objects.isNull(canteenId) ? -1 : canteenId);
                Long stallId = orderInfoAddParam.getStallId();
                orderInfo.setStallId(Objects.isNull(stallId) ? -1 : stallId);
                orderInfo.setOrderDate(orderInfoAddParam.getOrderDate());
                orderInfo.setOrderType(orderInfoAddParam.getOrderType());
                Integer mealtimeType = orderInfoAddParam.getMealtimeType();
                orderInfo.setMealtimeType(Objects.isNull(mealtimeType) ? -1 : mealtimeType);
                orderInfo.setMealtimeName(orderInfoAddParam.getMealtimeName());
                orderInfo.setIsOnline(Objects.isNull(param.getIsOnline()) ? 1 : param.getIsOnline());
                orderInfo.setOrderState(OrderStateEnum.WAIT_PLACE.getKey());
                orderInfo.setOrderRefundState(OrderRefundStateEnum.UN_REFUND.getKey());
                orderInfo.setDeductionType(DeductionTypeEnum.PAY_PLACE.getKey());
                orderInfo.setPayType(param.getPayType());
                orderInfo.setPayChannel(PayChannelEnum.ACC.getKey());
                orderInfo.setPayState(PayStateEnum.PAY_INPROCESS.getKey());
                orderInfo.setDeliveryAmount(BigDecimal.ZERO);
                orderInfo.setPackingAmount(BigDecimal.ZERO);
                orderInfo.setDeliveryType(DeliveryTypeEnum.SELF_TAKE.getKey());
                orderInfo.setCommentState(CommentStateEnum.UN_COMMENT.getKey());
                orderInfo.setOrderTime(DateUtils.getNowDate());
                orderInfo.setPayableAmount(BigDecimal.ZERO);
                orderInfo.setDiscountsAmount(BigDecimal.ZERO);
                orderInfo.setRealAmount(BigDecimal.ZERO);
                orderInfo.setExternalPayAmount(BigDecimal.ZERO);
                orderInfo.setRefundAmount(BigDecimal.ZERO);
                List<DeviceOrderDetailInfoAddParam> orderDetailInfoAddParams =orderInfoAddParam.getOrderDetailList();
                if(CollUtil.isNotEmpty(orderDetailInfoAddParams)) {
                    List<OrderDetail> orderDetailList = CollUtil.newArrayList();
                    for(DeviceOrderDetailInfoAddParam orderDetailInfoAddParam : orderDetailInfoAddParams) {
                        OrderDetail orderDetail = getOrderDetail(orderDetailInfoAddParam, orderInfo);
                        orderDetailList.add(orderDetail);
                        BigDecimal saleTotalAmount = orderDetail.getSalePrice().multiply(new BigDecimal(orderDetail.getQuantity()));
                        BigDecimal discountTotalAmount = orderDetail.getDiscountPrice().multiply(new BigDecimal(orderDetail.getQuantity()));
                        orderInfo.setPayableAmount(orderInfo.getPayableAmount().add(saleTotalAmount));
                        orderInfo.setDiscountsAmount(orderInfo.getDiscountsAmount().add(discountTotalAmount));
                        orderInfo.setRealAmount(orderInfo.getRealAmount().add(orderDetail.getTotalAmount()));
                        orderInfo.setAccountPayAmount(orderInfo.getRealAmount());
                    }
                    orderInfo.setOrderDetailList(orderDetailList);
                }
                orderInfoList.add(orderInfo);
            }
        }
        return orderInfoList;
    }

    private OrderDetail getOrderDetail(DeviceOrderDetailInfoAddParam orderDetailInfoAddParam, OrderInfo orderInfo) {
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderDate(orderInfo.getOrderDate());
        orderDetail.setGoodsId(orderDetailInfoAddParam.getGoodsId());
        orderDetail.setGoodsName(orderDetailInfoAddParam.getGoodsName());
        orderDetail.setGoodsImgUrl(orderDetailInfoAddParam.getGoodsImgUrl());
        orderDetail.setRecipeDetailId(orderDetailInfoAddParam.getMenuDetailId());
        orderDetail.setSalePrice(orderDetailInfoAddParam.getSalePrice());
        orderDetail.setDiscountPrice(orderDetailInfoAddParam.getDiscountPrice());
        orderDetail.setFinalPrice(orderDetailInfoAddParam.getFinalPrice());
        orderDetail.setQuantity(orderDetailInfoAddParam.getQuantity());
        orderDetail.setSalesMode(orderDetailInfoAddParam.getSalesMode());
        orderDetail.setDetailType(orderDetailInfoAddParam.getDetailType());
        BigDecimal totalAmount = orderDetail.getFinalPrice().multiply(new BigDecimal(orderDetail.getQuantity()));
        orderDetail.setTotalAmount(totalAmount);
        orderDetail.setCalcTotalAmount(totalAmount);
        orderDetail.setRealAmount(totalAmount);
        orderDetail.setDetailState(OrderDetailStateEnum.NORMAL.getKey());
        orderDetail.setRefundAmount(BigDecimal.ZERO);
        orderDetail.setRefundNum(0);
        orderDetail.setDeviceSn(StringUtils.defaultString(orderInfo.getDeviceSn(), StringUtils.EMPTY));
        orderDetail.setSerialNum(StringUtils.EMPTY);
        orderDetail.setCreateBy(SecurityUtils.getUsername());
        orderDetail.setCreateTime(DateUtils.getNowDate());
        orderDetail.setUpdateBy(SecurityUtils.getUsername());
        orderDetail.setUpdateTime(DateUtils.getNowDate());
        return orderDetail;
    }
}
