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

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
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 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;


/**
 * 订单 导出封装类
 *
 * @author zhengYi
 */
@Data
@ApiModel("管理后台 - 订单 导出封装类")
public class OrderExcelVO {

    @ExcelProperty("唛头")
    private String marks;

    @ExcelProperty("产品类型")
    @ExcelIgnore
    private Integer prodType;

    @ExcelProperty("产品标题")
    @ApiModelProperty(value = "产品标题")
    private String prodTitle;

    @ExcelProperty("产品中文标题")
    @ExcelIgnore
    private String prodTitleZh;

    @ExcelProperty("产品英文标题")
    @ExcelIgnore
    private String prodTitleEn;

    @ExcelProperty("备案")
    private String brandName;

    @ExcelProperty("箱数")
    private Integer num;

    @ExcelIgnore
    private String unit;

    @ExcelProperty("单位")
    private String unitName;

    @ExcelProperty("立方米")
    private BigDecimal volume;

    @ExcelProperty("重量")
    private BigDecimal weight;

    @ExcelProperty("订单总箱数")
    private Integer totalNum;

    @ExcelProperty("订单总方数")
    private BigDecimal totalVolume;

    @ExcelProperty("订单总重量")
    private BigDecimal totalWeight;

    @ExcelProperty("发货人")
    private String consignorName;

    @ExcelProperty("发货人电话")
    private String consignorPhone;

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

    @ExcelProperty("收货人")
    private String consigneeName;

    @ExcelProperty("收货人电话")
    private String consigneePhone;

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

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

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

    @ExcelProperty("订单编号")
    private String orderNo;

    @ExcelProperty("储位")
    private String storageLocation;

    @ExcelProperty("始发仓")
    private String startWarehouseName;

    @ExcelProperty("目的仓")
    private String destWarehouseName;

    @ExcelProperty(value = "入仓时间")
    @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    private Date rucangTime;


    /**
     * 入仓信息json
     */
    @ExcelIgnore
    @ApiModelProperty(value = "入仓信息VO")
    private WarehouseInInfoVO warehouseInInfoVO;

    /**
     * 入仓信息json
     */
    @ExcelIgnore
    @ApiModelProperty(value = "入仓信息json")
    private String warehouseInInfo;

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


    @ExcelProperty(value = "控货")
    private String cargoControlTitle;

    @ExcelProperty("数量")
    private Integer quantity;


    @ExcelProperty("货值")
    private String worth;


    @ExcelProperty(value = "订单状态")
    private String statusMsg;

    @ExcelProperty("日期(该状态最新日期)")
    @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    @ApiModelProperty(value = "更新日期", required = true)
    private Date updateTime;

    @ExcelProperty("费用类型")
    @ExcelIgnore
    private String feeType;

    @ExcelProperty("费用备注")
    @ExcelIgnore
    private String feeRemarks;


    @ExcelProperty("提单号")
    private String tidanNo;


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

    @ExcelIgnore
    @ApiModelProperty(value = "运输方式id")
    private Integer transportId;

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

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

    @ExcelIgnore
    @ApiModelProperty(value = "业务员ID")
    private Long salesmanId;

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


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


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

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

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

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

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

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

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

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


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

    @ExcelIgnore
    @ApiModelProperty("控货人")
    private String cargoControlName;

    @ExcelIgnore
    @ApiModelProperty(value = "控货人手机")
    private String cargoControlPhone;
    @ExcelIgnore
    @ApiModelProperty(value = "不阻塞流程的异常说明(支持多个异常说明)")
    private String exceptionReason;
    @ExcelIgnore
    @ApiModelProperty(value = "不阻塞流程的异常说明(支持多个异常说明)")
    private List<OrderRemindExceptionDto> remindExceptionDtoList;


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

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

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

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

    @ExcelIgnore
    @ApiModelProperty(value = "是否在公海")
    private Boolean isInOpenSea;

    public void setWarehouseInInfo(String warehouseInInfo) {
        this.warehouseInInfo = warehouseInInfo;
        if (StringUtils.isNotBlank(warehouseInInfo)) {
            this.warehouseInInfoVO = JSONObject.parseObject(warehouseInInfo, WarehouseInInfoVO.class);
        }
    }


    public void setLang(Integer lang) {
        this.lang = lang;
        this.getOrderDesc();
        if (Objects.nonNull(this.lang) && StringUtils.isNotBlank(this.unit)) {
            DictDataRespDTO respDTO = DictFrameworkUtils.getDictDataFromCache("packaging_type", unit);
            this.unitName = Objects.nonNull(respDTO) ? (this.lang == 0 ? respDTO.getLabel() : respDTO.getLabelEn()) : "箱";
        }
        if (Objects.nonNull(this.lang) &&Objects.nonNull(this.customsType)) {
            DictDataRespDTO respDTO = DictFrameworkUtils.getDictDataFromCache("customs_type", String.valueOf(customsType));
            this.customsTypeName = Objects.nonNull(respDTO) ? (this.lang == 0 ? respDTO.getLabel() : respDTO.getLabelEn()) : "我司全代";
        }
        if (StringUtils.isNotBlank(exceptionReason) && Objects.nonNull(this.lang)) {
            this.remindExceptionDtoList = JSONObject.parseArray(exceptionReason, OrderRemindExceptionDto.class)
                    .stream()
                    .peek(ern -> ern.setReason(this.lang == 0 ? I18nMessage.getZhMessage(ern.getReason()) : I18nMessage.getEnMessage(ern.getReason())))
                    .collect(Collectors.toList());
        }
    }


    public void setUnit(String unit) {
        this.unit = unit;
        if (Objects.nonNull(this.lang) && StringUtils.isNotBlank(this.unit)) {
            DictDataRespDTO respDTO = DictFrameworkUtils.getDictDataFromCache("packaging_type", unit);
            this.unitName = Objects.nonNull(respDTO) ? (this.lang == 0 ? respDTO.getLabel() : respDTO.getLabelEn()) : "箱";
        }
    }

    public void setCustomsType(Integer customsType) {
        this.customsType = customsType;
        if (Objects.nonNull(this.lang) &&Objects.nonNull(this.customsType)) {
            DictDataRespDTO respDTO = DictFrameworkUtils.getDictDataFromCache("customs_type", String.valueOf(customsType));
            this.customsTypeName = Objects.nonNull(respDTO) ? (this.lang == 0 ? respDTO.getLabel() : respDTO.getLabelEn()) : "我司全代";
        }
    }

    public void setIsCargoControl(Boolean isCargoControl) {
        this.isCargoControl = isCargoControl;
        this.cargoControlTitle = isCargoControl ? "是" : "否";
    }

    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 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) {
            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 (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);
        }
    }

}
