package cn.iocoder.yudao.module.order.vo.order;

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.module.order.dto.OrderRemindExceptionDto;
import cn.iocoder.yudao.module.order.enums.OrderAbnormalStateEnum;
import cn.iocoder.yudao.module.order.enums.OrderStatusEnum;
import cn.iocoder.yudao.module.order.enums.OrderStatusMsgEnum;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;

/**
 * 订单 Response VO
 *
 * @author 系统管理员
 */
@Data
@ApiModel("管理后台 - 订单 OrderBackPageVO VO")
@Slf4j
public class OrderBackPageVO {

    @ExcelProperty("主键ID")
    @ApiModelProperty(value = "主键ID", required = true)
    private Long orderId;

    @ExcelProperty("订单编号")
    @ApiModelProperty(value = "订单编号", required = true)
    private String orderNo;

    @ExcelProperty("提单编号")
    @ApiModelProperty(value = "提单编号")
    private String tidanNo;

    @ExcelProperty("父编号")
    @ApiModelProperty(value = "父编号")
    private String parentNumber;

    /**
     * 父订单id
     */
    @ApiModelProperty(value = "父订单id")
    private Long parentOrderId;

    @ApiModelProperty(value = "初始母订单id")
    private Long initialParentOrderId;

    @ApiModelProperty(value = "初始母订单编号")
    private String initialParentOrderNo;

    @ExcelProperty("货柜自编号")
    @ApiModelProperty(value = "货柜自编号")
    private String containerNumber;

    @ExcelProperty("运输方式id")
    @ApiModelProperty(value = "运输方式id", required = true)
    private Integer transportId;

    @ApiModelProperty(value = "订单服务类型(可多选)：1 集运服务 2 海外仓")
    private String type;

    @ApiModelProperty(value = "订单属性：1 普货 2 重货 3 泡货")
    private Integer orderType;

    @ApiModelProperty(value = "客户经理ID")
    private Long salesmanId;

    @ApiModelProperty(value = "业务员名称")
    private String salesmanName;

    @ApiModelProperty(value = "客户经理所属部门ID")
    private Long deptId;

    @ApiModelProperty(value = "用户ID")
    private Long userId;

    @ExcelProperty("唛头")
    @ApiModelProperty(value = "唛头")
    private String marks;

    @ExcelProperty("产品备案属性：1有牌,2无牌,3中性,4混牌")
    @ApiModelProperty(value = "产品备案属性：1有牌,2无牌,3中性,4混牌")
    private Integer productRecord;

    @ExcelProperty("是否控货")
    @ApiModelProperty(value = "是否控货")
    private Boolean isCargoControl;

    @ExcelProperty("0 控货中；1 已放完货；2 部分控货")
    @ApiModelProperty(value = "0 控货中；1 已放完货；2 部分控货")
    private Integer cargoControlStatus;

    @ExcelProperty("报关类别：我司全代：1，自单代报：2，混合报关：3")
    @ApiModelProperty(value = "报关类别：我司全代：1，自单代报：2，混合报关：3")
    private Integer customsType;

    @ExcelProperty("订单状态详情见字典")
    @ApiModelProperty(value = "订单状态详情见字典：order_status")
    private Integer status;

    @ExcelProperty("订单异常状态")
    @ApiModelProperty(value = "订单异常状态(字典 order_abnormal_state)")
    private Integer abnormalState;

    @ExcelProperty("订单入仓状态")
    @ApiModelProperty(value = "订单入仓状态(字典 order_warehouse_in_status)")
    private Integer inWarehouseState;

    @ExcelProperty("订单出货状态")
    @ApiModelProperty(value = "订单出货状态(字典 order_shipment_state)")
    private Integer shipmentState;

    @ExcelProperty("审核类型(字典 order_approval_type) 0 为正常")
    @ApiModelProperty(value = "审核类型(字典 order_approval_type) 0 为正常")
    private Integer auditType;

    @ExcelProperty("审核结果")
    @ApiModelProperty(value = "审核结果")
    private String auditResult;

    @ExcelProperty("入仓数量")
    @ApiModelProperty(value = "入仓数量")
    private Integer sumQuantity;

    @ExcelProperty("入仓件数")
    @ApiModelProperty(value = "入仓件数", required = true)
    private Integer sumNum;

    @ExcelProperty("入仓体积")
    @ApiModelProperty(value = "入仓体积", required = true)
    private BigDecimal sumVolume;

    @ExcelProperty("入仓重量")
    @ApiModelProperty(value = "入仓重量", required = true)
    private BigDecimal sumWeight;

    @ApiModelProperty(value = "重货体积")
    private BigDecimal wVolume;

    @ApiModelProperty(value = "泡货重量")
    private BigDecimal vWeight;

    @ExcelProperty("下单的客户id")
    @ApiModelProperty(value = "下单的客户id", required = true)
    private Long customerId;

    /**
     * 完成入仓的入仓体积
     */
    @ApiModelProperty(value = "完成入仓的入仓体积")
    private BigDecimal sumVolumeFinishedWarehouseIn;
    /**
     * 完成入仓的入仓重量
     */
    @ApiModelProperty(value = "完成入仓的入仓重量")
    private BigDecimal sumWeightFinishedWarehouseIn;


    @ExcelProperty("总件数")
    @ApiModelProperty(value = "总件数", required = true)
    private Integer totalNum;


    @ExcelProperty("创建时间")
    @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    @ApiModelProperty(value = "创建时间", required = true)
    private Date createTime;

    @ExcelProperty("收货人姓名")
    @ApiModelProperty(value = "收货人姓名")
    private String consigneeName;

    @ExcelProperty("收货人姓名(英文)")
    @ApiModelProperty(value = "收货人姓名(英文)")
    private String consigneeNameEn;

    @ExcelProperty("收货人手机")
    @ApiModelProperty(value = "收货人手机")
    private String consigneePhone;

    @ApiModelProperty(value = "收货人手机国家区号")
    private String consigneeCountryCode;

    @ExcelProperty("发货人姓名")
    @ApiModelProperty(value = "发货人姓名")
    private String consignorName;

    @ExcelProperty("发货人姓名(英文)")
    @ApiModelProperty(value = "发货人姓名(英文)")
    private String consignorNameEn;

    @ExcelProperty("发货人手机")
    @ApiModelProperty(value = "发货人手机")
    private String consignorPhone;

    @ApiModelProperty(value = "发货人手机国家区号")
    private String consignorCountryCode;

    @ExcelProperty("控货人姓名")
    @ApiModelProperty(value = "控货人姓名")
    private String cargoControlName;

    @ExcelProperty("控货人姓名(英文)")
    @ApiModelProperty(value = "控货人姓名(英文)")
    private String cargoControlNameEn;

    @ExcelProperty("控货人手机")
    @ApiModelProperty(value = "控货人手机")
    private String cargoControlPhone;

    @ExcelProperty("控货人手机国家区号")
    @ApiModelProperty(value = "控货人手机国家区号")
    private String cargoControlCountryCode;

    @ExcelProperty(value = "特需类型")
    @ApiModelProperty(value = "特需类型")
    private String advanceType;


    @ApiModelProperty(value = "始发地ID")
    private Long departureId;

    @ApiModelProperty(value = "目的地ID")
    private Long objectiveId;

    @ApiModelProperty(value = "始发地名称")
    private String departureName;

    @ApiModelProperty(value = "目的地名称")
    private String objectiveName;


    @ApiModelProperty(value = "始发仓库ID")
    private Long startWarehouseId;

    @ApiModelProperty(value = "目的仓库ID")
    private Long dstWarehouseId;

    @ExcelProperty(value = "始发仓库")
    @ApiModelProperty(value = "始发仓库")
    private String startWarehouseName;

    @ExcelProperty(value = "目的仓库")
    @ApiModelProperty(value = "目的仓库")
    private String dstWarehouseName;


    @ApiModelProperty(value = "调仓始发仓id")
    private Long adjustToStartWarehouseId;
    /**
     * 调仓目的仓
     */
    @ApiModelProperty(value = "调仓目的仓id")
    private Long adjustToDestWarehouseId;

    @ExcelProperty("调仓后的始发仓")
    @ApiModelProperty(value = "调仓后的始发仓")
    private String adjustToStartWarehouseName;

    @ExcelProperty("调仓后的目的仓")
    @ApiModelProperty(value = "调仓后的目的仓")
    private String adjustToDestWarehouseName;


    @ApiModelProperty(value = "目的地调仓-始发仓id")
    private Long destAdjustToStartWarehouseId;

    @ApiModelProperty(value = "目的地调仓-目的仓id")
    private Long destAdjustToDestWarehouseId;

    @ExcelProperty("目的地调-始发仓")
    @ApiModelProperty(value = "目的地调仓-始发仓")
    private String destAdjustToStartWarehouseName;

    @ExcelProperty("目的地调仓-目的仓")
    @ApiModelProperty(value = "目的地调仓-目的仓")
    private String destAdjustToDestWarehouseName;

    @ApiModelProperty(value = "不阻塞流程的异常说明(支持多个异常说明)")
    private String exceptionReason;

    @ApiModelProperty(value = "不阻塞流程的异常说明(支持多个异常说明)")
    private List<OrderRemindExceptionDto> remindExceptionDtoList;

    @ApiModelProperty(value = "是否有异常(此处为不阻塞流程的异常)")
    private Boolean isException = Boolean.FALSE;

    @ApiModelProperty(value = "费用清单及下单统计")
    @ExcelIgnore
    private String cost;

    @ApiModelProperty(value = "费用清单及下单统计VO")
    @ExcelIgnore
    private CostVO costVO;


    @ExcelProperty(value = "费用清单")
    private String feeCost;


    /**
     * 入仓时间
     */
    @ApiModelProperty(value = "入仓时间")
    private Date rucangTime;


    @ApiModelProperty(value = "首次入仓时间")
    private Date inTime;

    @ApiModelProperty(value = "已装柜时间")
    private Date loadTime;


    /**
     * 渠道名称
     */
    @ApiModelProperty(value = "渠道名称")
    private String channelName;

    @ExcelProperty("当前控货箱数")
    @ApiModelProperty(value = "当前控货箱数")
    private Integer controlNum;

    @ApiModelProperty(value = "当前控货数量")
    private Integer controlQuantity;

    @ApiModelProperty(value = "当前控货箱数")
    private BigDecimal controlVolume;

    @ApiModelProperty(value = "当前控货箱数")
    private BigDecimal controlWeight;

    @ApiModelProperty(value = "已放货箱数")
    private Integer releaseNum;

    @ApiModelProperty(value = "放货数量")
    private Integer releaseQuantity;

    @ApiModelProperty(value = "放货体积")
    private BigDecimal releaseVolume;

    @ApiModelProperty(value = "放货重量")
    private BigDecimal releaseWeight;

    /**
     * 是否为我控货
     */
    @ApiModelProperty(value = "是否为我控货")
    private Boolean cargoController = Boolean.FALSE;
    /**
     * 是否为我发货
     */
    @ApiModelProperty(value = "是否为我发货")
    private Boolean deliverGoods = Boolean.FALSE;
    /**
     * 是否为我收货
     */
    @ApiModelProperty(value = "是否为我收货")
    private Boolean receiving = Boolean.FALSE;

    @ApiModelProperty(value = "是否外部仓")
    private Boolean isExternalWarehouse = Boolean.FALSE;
    /**
     * 报价单ID
     */
    @ApiModelProperty(value = "报价单ID")
    private Long offerId;
    /**
     * 报价单状态
     */
    @ApiModelProperty(value = "报价单状态")
    private Integer offerStatus;

    /**
     * 状态说明
     */
    @ApiModelProperty(value = "状态说明")
    private String statusMsg;


    /**
     * 关联订单状态
     */
    @ApiModelProperty(value = "关联订单状态")
    private String guanLianOrderStatus;

    @ApiModelProperty(value = "关联订单状态")
    private List<GuanLianOrderStatusVO> guanLianOrderStatusVOList;

    @ApiModelProperty(value = "目的港清关：1 我司 2 客户")
    private Integer portDestCustomsClear;

    @ApiModelProperty(value = "发货方式：1 多票 2 单票")
    private Integer deliveryWay;

    @ApiModelProperty(value = "清关证书备注")
    private String customsClearCertRemarks;

    @ApiModelProperty(value = "空运可出货状态： 0 默认值 1 待出 2 可出 3 备货中 4 已备货")
    private Integer airShipment;

    @ApiModelProperty(value = "特价泡重")
    private BigDecimal specialVWeight;

    @ApiModelProperty(value = "是否处理了渠道特性异常")
    private Boolean handlerChannelAttrException;

    @ApiModelProperty(value = "打包前入仓重量")
    private BigDecimal weightBeforePack;


    @ApiModelProperty(value = "打包后入仓重量")
    private BigDecimal weightAfterPack;

    @ApiModelProperty(value = "备货重量阀值")
    private BigDecimal stockOverWeightLimit;

    @ApiModelProperty(value = "拆单子订单是作为独立订单计算(拆单业务只要涉及到空运即将所有拆单后的子订单作为独立订单来计算)")
    private Boolean splitSeparateOrder = false;


    @ApiModelProperty(value = "是否显示提单金额")
    private Boolean displayBillLadingPrice = true;

    /**
     * 状态key(前端在订单列表做权限按钮判断)
     */
    @ApiModelProperty(value = "订单列表权限按钮判断状态key")
    private Integer statusKey;

    @ApiModelProperty(value = "控货订单是否有待复核记录")
    private Boolean isToReview;

    @ApiModelProperty(value = "控货订单是否有放完货可以进行调货与反复核的记录")
    private Boolean isReleaseAfterGoods;

    /**
     * 端口 {@link UserTypeEnum}
     */
    @ApiModelProperty(value = "端口(默认管理端)")
    private Integer userType = 2;

    @ApiModelProperty(value = "语言")
    private Integer lang;


    public void setGuanLianOrderStatus(String guanLianOrderStatus) {
        this.guanLianOrderStatus = guanLianOrderStatus;
        if (StringUtils.isNotBlank(guanLianOrderStatus)) {
            this.guanLianOrderStatusVOList = JSONObject.parseArray(guanLianOrderStatus, GuanLianOrderStatusVO.class);
            this.getOrderDesc();
        }
    }

    public void setGuanLianOrderStatusVOList(List<GuanLianOrderStatusVO> guanLianOrderStatusVOList) {
        this.guanLianOrderStatusVOList = guanLianOrderStatusVOList;
        if (CollectionUtil.isNotEmpty(guanLianOrderStatusVOList)) {
            this.guanLianOrderStatus = JSONObject.toJSONString(guanLianOrderStatusVOList);
        }
    }


    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo.contains("DRAFT") ? null : orderNo;
    }

    public void setStatus(Integer status) {
        this.status = status;
        this.getOrderDesc();

    }

    public void setAbnormalState(Integer abnormalState) {
        this.abnormalState = abnormalState;
        this.getOrderDesc();
    }

    public void setInWarehouseState(Integer inWarehouseState) {
        this.inWarehouseState = inWarehouseState;
        this.getOrderDesc();
    }

    public void setAirShipment(Integer airShipment) {
        this.airShipment = airShipment;
        this.getOrderDesc();
    }

    public void setShipmentState(Integer shipmentState) {
        this.shipmentState = shipmentState;
        this.getOrderDesc();
    }

    public void setAuditType(Integer auditType) {
        this.auditType = auditType;
        this.getOrderDesc();
    }

    public void setAuditResult(String auditResult) {
        this.auditResult = auditResult;
        this.getOrderDesc();

    }

    public void setLang(Integer lang) {
        this.lang = lang;
        if (StringUtils.isNotBlank(this.exceptionReason) && Objects.nonNull(lang)) {
            this.remindExceptionDtoList = JSONObject.parseArray(this.exceptionReason, OrderRemindExceptionDto.class)
                    .stream()
                    .peek(ern -> ern.setReason(lang == 0 ? I18nMessage.getZhMessage(ern.getReason()) : I18nMessage.getEnMessage(ern.getReason())))
                    .collect(Collectors.toList());
        }
        this.getOrderDesc();
    }

    public void setExceptionReason(String exceptionReason) {
        this.exceptionReason = exceptionReason;
        if (StringUtils.isNotBlank(exceptionReason) && Objects.nonNull(this.lang)) {
            this.remindExceptionDtoList = JSONObject.parseArray(exceptionReason, OrderRemindExceptionDto.class)
                    .stream()
                    .peek(ern -> ern.setReason(lang == 0 ? I18nMessage.getZhMessage(ern.getReason()) : I18nMessage.getEnMessage(ern.getReason())))
                    .collect(Collectors.toList());
        }
        this.getOrderDesc();
    }

    private void getOrderDesc() {
        // TODO 这里的文案国际化现在只支持两种语言，如果需要支持更多的语言，需要优化
        Integer lang = Objects.nonNull(this.lang) ? this.lang : I18nMessage.getLang();
        if (null != this.status && this.status.equals(OrderStatusEnum.CANCEL.getValue()) && this.userType != null) {
            String message = this.userType == 2 ? OrderStatusMsgEnum.CANCEL.getAdminSourceName() : OrderStatusMsgEnum.CANCEL.getCustomerSourceName();
            this.statusMsg = lang == 0 ? I18nMessage.getZhMessage(message) : I18nMessage.getEnMessage(message);
        } else if (null != this.abnormalState && this.abnormalState > 0) {
            this.statusKey = 10000;
            OrderAbnormalStateEnum abnormalStateEnum = OrderAbnormalStateEnum.valueOf(abnormalState);
            if (Objects.isNull(abnormalStateEnum)) {
                this.statusMsg = lang == 0 ? "未知异常" : "UNKNOWN_EXCEPTION";
            } else {
                this.statusMsg = lang == 0 ? I18nMessage.getZhMessage(abnormalStateEnum.getDesc()) : I18nMessage.getEnMessage(abnormalStateEnum.getDesc());
            }
        } else if (StringUtils.isNotBlank(this.auditResult)) {
            this.statusMsg = lang == 0 ? I18nMessage.getZhMessage(auditResult) : I18nMessage.getEnMessage(auditResult);
        } else if (CollectionUtil.isNotEmpty(this.remindExceptionDtoList) && this.remindExceptionDtoList.size() > 0) {
            this.statusMsg = remindExceptionDtoList.get(0).getReason();
        } else if (null != this.status && this.status == 5
                && CollectionUtil.isNotEmpty(this.guanLianOrderStatusVOList)) {
            // 已入仓的订单才展示关联异常信息
            // 如果查询返回了关联订单状态，表示需要显示关联订单状态，关联订单状态冗余的是国际化key值
            // 排序
            this.guanLianOrderStatusVOList = this.guanLianOrderStatusVOList.stream().sorted(Comparator.comparing(GuanLianOrderStatusVO::getType)).collect(Collectors.toList());
            GuanLianOrderStatusVO guanlianOrderStatusVO = guanLianOrderStatusVOList.get(0);
            switch (guanlianOrderStatusVO.getType()) {
                case 1:
                    // 关联异常状态封装，订单状态显示“关联单#订单号#，#异常名称#”Associated order %s, %s
                    String abnormalMsg = lang == 0 ? I18nMessage.getZhMessage("guanlian.order.abnormalState") : I18nMessage.getEnMessage("guanlian.order.abnormalState");
                    this.statusMsg = String.format(abnormalMsg, guanlianOrderStatusVO.getOrderNo(), I18nMessage.getMessage(guanlianOrderStatusVO.getStatusMsg()));
                    break;
                case 2:
                    // 关联审批状态封装，订单状态显示“关联单#订单号##审核状态#”
                    String auditMsg = lang == 0 ? I18nMessage.getZhMessage("guanlian.order.audit") : I18nMessage.getEnMessage("guanlian.order.audit");
                    this.statusMsg = String.format(auditMsg, guanlianOrderStatusVO.getOrderNo(), I18nMessage.getMessage(guanlianOrderStatusVO.getStatusMsg()));
                    break;
                case 3:
                    // 关联未入仓状态封装，订单状态显示“关联单#订单号#未入仓”
                    String waitWarehouseInMsg = lang == 0 ? I18nMessage.getZhMessage(guanlianOrderStatusVO.getStatusMsg()) : I18nMessage.getEnMessage(guanlianOrderStatusVO.getStatusMsg());
                    this.statusMsg = String.format(waitWarehouseInMsg, guanlianOrderStatusVO.getOrderNo());
                    break;
                default:
                    this.statusMsg = lang == 0 ? I18nMessage.getZhMessage(guanlianOrderStatusVO.getStatusMsg()) : I18nMessage.getEnMessage(guanlianOrderStatusVO.getStatusMsg());
            }
        } else if (null != this.status && null != this.inWarehouseState &&
                null != this.shipmentState && null != this.airShipment &&
                null != this.transportId) {
            this.statusMsg = OrderStatusMsgEnum.getMsg(this.status,
                    this.inWarehouseState, this.shipmentState,
                    this.airShipment, this.transportId,
                    this.userType, lang);

//            this.statusKey = OrderStatusMsgEnum.getStatusKey(this.status, this.inWarehouseState, this.shipmentState);
        }
    }


    public String getCost() {
        return cost;
    }

    public void setCost(String cost) {
        this.cost = cost;
        this.costVO = JSONObject.parseObject(this.cost, CostVO.class);
    }

    public void setCostVO(CostVO costVO) {
        this.costVO = costVO;
        this.cost = JSONObject.toJSONString(costVO);
    }

    public CostVO getCostVO() {
        return JSONObject.parseObject(this.cost, CostVO.class);
    }


}
