package com.ximai.mes.pro.schedule;

import cn.hutool.core.bean.BeanUtil;
import com.ximai.common.annotation.Excel;
import com.ximai.mes.pro.domain.productionSolution.ProProductionSolutionProcess;
import com.ximai.mes.pro.domain.productionSolution.ProProductionSolutionSpecificationSheet;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.*;

@Data
public class Task {

    public Task(Long id, Job job, List<Equipment> optionalEquipments, IOperationTimeCalculator operationTimeCalculator, ILimitedTimeCalculator limitedTimeCalculator)
    {
        this.id = id;
        this.job = job;
        this.optionalEquipments = optionalEquipments;
        this.operationTimeCalculator = operationTimeCalculator;
        this.limitedTimeCalculator = limitedTimeCalculator;
        taskData = new HashMap<String, Object>();

        this.lmtStartedTime = new OptionalTimeSpan(OptionalTimeSpan.Type.Max);
        this.lmtEndedTime = new OptionalTimeSpan(OptionalTimeSpan.Type.Min);

        this.lmtStartedTime.addOptional(() -> job.getLmtStartedTime().get());
        this.lmtEndedTime.addOptional(() -> job.getLmtEndedTime().get());

        scheduleStatus = ScheduleStatus.UnScheduled;
    }

    public Task(Long id, Job job)
    {
        this.id = id;
        this.job = job;
        taskData = new HashMap<String, Object>();

        this.lmtStartedTime = new OptionalTimeSpan(OptionalTimeSpan.Type.Max);
        this.lmtEndedTime = new OptionalTimeSpan(OptionalTimeSpan.Type.Min);

        this.lmtStartedTime.addOptional(() -> job.getLmtStartedTime().get());
        this.lmtEndedTime.addOptional(() -> job.getLmtEndedTime().get());

        scheduleStatus = ScheduleStatus.UnScheduled;
    }

    /*
     * Id
     */
    private Long id;

    /*
     * Job
     */
    private Job job;

    private Long processId;

    /**
     * 工序名
     */
    private String processName;

    /**
     * 工序序列号
     */
    private String idx;

    /**
     * 标准工时
     */
    private BigDecimal stdWorkingTime;

    /**
     * 工时单位
     */
    private String stdWorkingTimeUom;

    /**
     * 单价
     */
    private BigDecimal unitPrice;

    /**
     * 工作中心名称
     */
    private Long workCenterId;

    /**
     * 工作中心名称
     */
    private String workCenterName;

    /**
     * 标准工时
     */
    private Duration standardWorkingTime;

    /**
     * 换型时间
     */
    private Duration setupTime=Duration.ZERO;

    /**
     * 订单数量
     */
    private BigDecimal orderQuantity;

    /**
     * 是否外委工序
     *
     */
    private boolean outsourced=false;



    /*
     * Task Data
     */
    private Map<String, Object> taskData;

    /*
     * 可选设备
     */
    private List<Equipment> optionalEquipments;

    /*
     * 排产设备
     */
    private Equipment scheduledEquipment;

    /*
     * 工作时间计算器
     */
    private IOperationTimeCalculator operationTimeCalculator;

    /*
     * 开始结束时间限制线计算器
     */
    private ILimitedTimeCalculator limitedTimeCalculator;

    /*
     * 开始时间限制线
     */
    private OptionalTimeSpan lmtStartedTime;

    /*
     * 结束时间限制线
     */
    private OptionalTimeSpan lmtEndedTime;

    /*
     * 排产开始时间
     */
    private Duration scheduledStartedTime;

    /*
     * 排产结束时间
     */
    private Duration scheduledEndedTime;

    /*
     * 排产结果
     */
    private ScheduleStatus scheduleStatus;

    /*
     * 作业日历
     */
    private List<Calendar.OccupiedCalendar> occupiedCalendar;

    private CalendarManager calendarManager;

    /*
     * 按设备拆分后的任务
     */
    List<Task> splitTask;

    /*
    上道任务
     */
    Task preTask;

    public List<Calendar.OccupiedCalendar> getOccupiedCalendar() {
        return calendarManager.getOccupiedCalendar(this);
    }

    /**
     * 工序功要求能点
     */
    @Data
    public static class ProcessFunction{

        /** 封切机开边 */
        @ApiModelProperty("封切机开边")
        private String sacmForEdgeOpening;

        /** 封切机粘贴复合 */
        @ApiModelProperty("封切机粘贴复合")
        private String sacmForPasteComposite;

        /** 封切机热复合 */
        @ApiModelProperty("封切机热复合")
        private String sacmForThermalComposite;

        /** 封切机贴标 */
        @ApiModelProperty("封切机贴标")
        private String sacmForLabeling;

        /** 封切机装扣 */
        @ApiModelProperty("封切机装扣")
        private String sacmForBuckleUp;

        /** 封切机压痕 */
        @ApiModelProperty("封切机压痕")
        private String sacmForCreasing;

        /** 封切机风琴 */
        @ApiModelProperty("封切机风琴")
        private String sacmForOrgan;

        /** 封切机热切 */
        @ApiModelProperty("封切机热切")
        private String sacmForThermalCutting;

        /** 封切机热自合 */
        @ApiModelProperty("封切机热自合")
        private String sacmForThermalSelfFusion;

        /** 封切机压齿 */
        @ApiModelProperty("封切机压齿")
        private String sacmForMolarTooth;

        /** 封切机分切 */
        @ApiModelProperty("封切机分切")
        private String sacmForSlitting;
    }

    /**
     * 工序加工要求属性
     */
    @Data
    public static class ProcessRequestAttribute{

        /**
         * 厚度mm
         */
        @ApiModelProperty("厚度mm")
        private BigDecimal thick;

        /**
         * 印刷宽度
         */
        @ApiModelProperty("印刷宽度")
        private BigDecimal printingWidth;

        /** 凹印_胶版油槽数 */
        @ApiModelProperty("凹印_胶版油槽数")
        private BigDecimal dieSunkOffsetOilTankNum;

        /**
         * 印刷方式
         * 单面印刷/双面印刷
         */
        @ApiModelProperty("印刷方式")
        private String printingMethod;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Task task = (Task) o;
        return Objects.equals(id, task.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
