package com.sw.mes.yb.plan.controller;

import com.alibaba.fastjson.JSONObject;
import com.sw.mes.base.factory.product.entity.NewProductModel;
import com.sw.mes.base.factory.product.entity.ProductModel;
import com.sw.mes.base.factory.product.service.NewProductModelService;
import com.sw.mes.base.workinprocess.dto.ProcessLogDto;
import com.sw.mes.base.workinprocess.entity.ProcessLog;
import com.sw.mes.core.annotation.Jinko;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.response.ResponsePage;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.*;
import com.sw.mes.base.factory.init.dto.Equipment.EquipmentDto;
import com.sw.mes.base.factory.init.dto.MachineCapacity.MachineCapacityDto;
import com.sw.mes.base.factory.init.dto.SeriesEquimentDto;
import com.sw.mes.base.factory.init.entity.Equipment;
import com.sw.mes.base.factory.init.entity.MachineCapacity;
import com.sw.mes.base.factory.init.service.EquipmentService;
import com.sw.mes.base.factory.init.service.MachineCapacityService;
import com.sw.mes.enumvalue.EnumValuesServer;
import com.sw.mes.yb.plan.dto.BatchSchedulingDto;
import com.sw.mes.yb.plan.dto.SchedulingInfoDto;
import com.sw.mes.yb.plan.entity.ProductionOrder;
import com.sw.mes.yb.plan.service.ProductionOrderService;
import com.sw.mes.yb.production.entity.LoadingTask;
import com.sw.mes.yb.production.service.LoadingTaskService;
import com.sw.mes.yb.scheduled.YbAutoScheduling;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.modelmapper.ModelMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Query;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import com.sw.mes.yb.plan.entity.ProductionSchedule;
import com.sw.mes.yb.plan.dto.ProductionScheduleDto;
import com.sw.mes.yb.plan.service.ProductionScheduleService;


/**
 * @Author
 * @Description：
 * @Date: Create in
 * @Modified By:
 */
@RestController
@RequestMapping("/productionSchedule")
@Slf4j
@Api(description = "圆棒工单排程接口")
public class ProductionScheduleController {
    @Autowired
    ModelMapper modelMapper;

    @Autowired
    private ProductionScheduleService productionScheduleService;

    @Autowired
    private MachineCapacityService machineCapacityService;

    @Autowired
    private NewProductModelService newProductModelService;

    @Autowired
    private ProductionOrderService productionOrderService;

    @Autowired
    private LoadingTaskService loadingTaskService;
    @Autowired
    private EquipmentService equipmentService;

    @ApiOperation(value = "查询设备最近几个进行/完成的炉次")
    @GetMapping("/queryLotNoByDeviceNo")
    public Result queryLotNoByDeviceNo(@RequestParam String deviceNo) {
        List<String> devices = productionScheduleService.queryLotNoByDeviceNo(deviceNo);
        return ResultGenerator.success(devices);
    }

    @ApiOperation(value = "查询当前设备进行状态工单的最近炉次")
    @GetMapping("/queryLotNosByDeviceNo")
    public Result<String> queryLotNosByDeviceNo(@RequestParam String deviceNo) {
        String devices = productionScheduleService.queryLotNosByDeviceNo(deviceNo);
        return ResultGenerator.success(devices);
    }

    @ApiOperation(value = "查询当前设备进行状态工单的最近炉次")
    @GetMapping("/queryLotNosByDeviceCode")
    public Result<String> queryLotNosByDeviceCode(@RequestParam String deviceNo) {
        Equipment equipment = equipmentService.findByCode(deviceNo);
        if(ObjectUtils.isEmpty(equipment)){
            return ResultGenerator.fail("未查询到该编码【"+deviceNo+"】的设备信息!");
        }
        String devices = productionScheduleService.queryLotNosByDeviceNo(deviceNo);
        return ResultGenerator.success(devices);
    }
    @ApiOperation(value = "分页查询圆棒工单排程列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "rows", value = "行数", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "page", value = "页码", dataType = "integer", paramType = "query"),
    })
    @GetMapping("/listByPage")
    public Result<ResponsePage<ProductionScheduleDto>> listByPage(ServletRequest request, @ApiIgnore RequestPage requestPage) {
        Specification<ProductionSchedule> specification = DynamicSpecifications.bySearchFilter(request, ProductionSchedule.class);
        String[] parameterValues = request.getParameterValues("search_EQ_productionOrder.id");
        if ((parameterValues != null) && (parameterValues.length != 0)) {
            requestPage.setOrderField("deviceNo");
            requestPage.setOrderDirection(RequestPage.ORDER_DIRECTION_ASC);
        }
        Page<ProductionSchedule> page = productionScheduleService.findByExample(specification, PageUtil.createPageable(requestPage));
        List<ProductionScheduleDto> dtos = page.getContent().stream()
                .map(entity -> toLazyDto(entity))
                .collect(Collectors.toList());

        // 补充高低阻字段
        for (ProductionScheduleDto dto : dtos) {
            NewProductModel model = newProductModelService.findByCode(dto.getProductModelCode());
            if (null != model) {
                dto.setResistanceType(model.getResistanceType());
            }
        }
        ResponsePage responsePage = new ResponsePage(dtos, page.getTotalElements());
        return ResultGenerator.success(responsePage);
    }

    @ApiOperation(value = "获取所有圆棒工单排程")
    @GetMapping("/listAll")
    public Result<List<ProductionScheduleDto>> listAll(ServletRequest request) {
        Specification<ProductionSchedule> specification = DynamicSpecifications.bySearchFilter(request, ProductionSchedule.class);
        List<ProductionSchedule> productionSchedules = productionScheduleService.findByExampleSort(specification, null);
        List<ProductionScheduleDto> productionScheduleDtos = productionSchedules.stream()
                .map(productionSchedule -> toLazyDto(productionSchedule))
                .collect(Collectors.toList());
        return ResultGenerator.success(productionScheduleDtos);
    }

    @ApiOperation(value = "圆棒工单排程详细信息")
    @GetMapping("/{id}")
    public Result<ProductionScheduleDto> get(@PathVariable @ApiParam(value = "圆棒工单排程id") Long id) {
        ProductionSchedule productionSchedule = productionScheduleService.get(id);
        if (null == productionSchedule) {
            return ResultGenerator.fail("该圆棒工单排程不存在");
        }
        return ResultGenerator.success(toEagerDto(productionSchedule));
    }

    @ApiOperation(value = "创建圆棒工单排程")
    @PostMapping("/create")
    public Result create(@RequestBody @Valid @ApiParam(value = "圆棒工单排程对象") ProductionScheduleDto productionScheduleDto, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        ProductionSchedule productionSchedule = fromDto(productionScheduleDto);
        productionScheduleService.saveOrUpdate(productionSchedule);
        return ResultGenerator.success();
    }

    @ApiOperation(value = "查询未开始的工单排程")
    @GetMapping("/query")
    public Result query(@RequestParam String code) {
        ProductionSchedule next_productionSchedule = productionScheduleService.findTopByDeviceNoAndStatusOrderByIdDesc(code, Arrays.asList(0));
        String s = JSONObject.toJSONString(next_productionSchedule);
        return ResultGenerator.success(s);
    }

    @ApiOperation(value = "根据任务id查询工单排程")
    @GetMapping("/findPlanProductionById")
    public Result<ProductionScheduleDto> findPlanProductionByCode(@RequestParam Long id) {
        ProductionSchedule productionSchedule = productionScheduleService.findPlanProductionById(id);
        ProductionScheduleDto eagerDto = toEagerDto(productionSchedule);
        Long productionOrderId = productionSchedule.getProductionOrder().getId();
        eagerDto.setProductionOrderId(Integer.valueOf(String.valueOf(productionOrderId)));
        eagerDto.setProductionOrderAuart(productionSchedule.getProductionOrder().getAuart());
        return ResultGenerator.success(eagerDto);
    }

    @Jinko(value = "配料任务管理", author = "wxl")
    @ApiOperation(value = "修改状态")
    @GetMapping("/updateStatus")
    public Result updateStatus(@ApiParam(value = "排程ID") @RequestParam Long scheduleId,
                               @ApiParam(value = "状态") @RequestParam Integer status) {
        try {
            ProductionSchedule schedule = productionScheduleService.get(scheduleId);
            if (ObjectUtils.isEmpty(schedule)) return ResultGenerator.fail("排程不存在");
            if (status == EnumValuesServer.ProductionScheduleStatus.待备料.getKey()){
                LoadingTask loadingTask = loadingTaskService.findSuccessByLotNo(schedule.getLotNo());
                if (ObjectUtils.isEmpty(loadingTask)){
                    schedule.setStatus(EnumValuesServer.ProductionScheduleStatus.待备料.getKey());
                    schedule.setStatusInfo(EnumValuesServer.ProductionScheduleStatus.待备料.getValue());
                }
            }else if (status == EnumValuesServer.ProductionScheduleStatus.已备料.getKey()){
                schedule.setStatus(EnumValuesServer.ProductionScheduleStatus.已备料.getKey());
                schedule.setStatusInfo(EnumValuesServer.ProductionScheduleStatus.已备料.getValue());
            }
            productionScheduleService.saveOrUpdate(schedule);
        } catch (Exception e) {
            log.error("更新排程状态：", e);
            return ResultGenerator.fail("排程状态更新失败");
        }
        return ResultGenerator.success();
    }


    @Jinko(value = "单晶生产工单", author = "wxl")
    @ApiOperation(value = "取消")
    @GetMapping("/cancel")
    public Result cancel(@ApiParam(value = "排程ID") Long id) {
        ProductionSchedule schedule = productionScheduleService.get(id);
        if (null == schedule) {
            return ResultGenerator.fail("该圆棒工单排程不存在");
        }
        if (schedule.getStatus() != EnumValuesServer.ProductionScheduleStatus.未开始.getKey()) {
            return ResultGenerator.fail("只有【未开始】状态的排查才能取消");
        }
        schedule.setStatus(EnumValuesServer.ProductionScheduleStatus.已取消.getKey());
        productionScheduleService.saveOrUpdate(schedule);

        // 修改订单排程状态
        productionScheduleService.setOrderSchedule(schedule.getProductionOrder(), 0);

        return ResultGenerator.success();
    }


    @ApiOperation(value = "更新圆棒工单排程")
    @PostMapping("/update")
    public Result update(@RequestBody @Valid @ApiParam(value = "圆棒工单排程") ProductionScheduleDto dto, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        if (dto.getId() == null) {
            return ResultGenerator.fail("id不能为空");
        }
        ProductionSchedule entity = productionScheduleService.get(dto.getId());
        if (entity == null) {
            return ResultGenerator.fail("原信息不存在");
        }
        try {
            ProductionSchedule entityfromFto = fromDto(dto);
            BeanUtils.copyProperties(entityfromFto, entity, BeanUtil.getIgnoreProperties(entityfromFto, null, null));
            productionScheduleService.saveOrUpdate(entity);
            return ResultGenerator.success();
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    /**
     * 批量排程
     *
     * @param
     * @return
     */
    @ApiOperation(value = "批量排程")
    @PostMapping("/batchScheduling")
    public Result batchScheduling(@RequestBody @Valid @ApiParam(value = "圆棒工单批量排程") BatchSchedulingDto dto, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        productionScheduleService.batchScheduling(dto);
        return ResultGenerator.success();
    }


    /**
     * 设备加工能力改变，排程调整
     */
    @ApiOperation(value = "设备加工能力改变")
    @GetMapping("/updateMachineCapacity")
    public Result updateMachineCapacity(@RequestParam Integer id) {
        try {
            productionScheduleService.updateMachineCapacity(id);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultGenerator.fail(e.getMessage());
        }
        return ResultGenerator.success();
    }


    /**
     * 获取设备排程情况
     *
     * @param
     * @return
     */
    @ApiOperation(value = "排程情况")
    @GetMapping("/getSchedulingInfo")
    public Result<List<SchedulingInfoDto>> getSchedulingInfo() {
        List<SchedulingInfoDto> list = productionScheduleService.getSchedulingInfo();
        return ResultGenerator.success(list);
    }

    @ApiOperation(value = "删除圆棒工单排程")
    @PostMapping("/delete")
    public Result remove(@ApiParam(value = "id集合,逗号分隔,如2,4", type = "query") @RequestParam Long[] ids) {
        for (Long id : ids) {
            productionScheduleService.delete(id);
        }
        return ResultGenerator.success();
    }

    @Autowired
    private YbAutoScheduling ybAutoScheduling;

    @ApiOperation(value = "触发自动排程")
    @GetMapping("/ybAutoScheduling")
    public Result ybAutoScheduling() {
        ybAutoScheduling.consumptionCutData();
        return ResultGenerator.success();
    }

    @ApiOperation(value = "触发自动圆棒检验数据查询定位头尾回收料")
    @GetMapping("/synBracketNoJobHandler")
    public Result synBracketNoJobHandler() {
        ybAutoScheduling.synBracketNoJobHandler();
        return ResultGenerator.success();
    }


    @ApiOperation(value = "导出单晶生产工单列表")
    @GetMapping("/export")
    public void export(ServletRequest request, HttpServletResponse response) {
        try {
            Specification<ProductionSchedule> specification = DynamicSpecifications.bySearchFilter(request, ProductionSchedule.class);
            List<ProductionSchedule> productionSchedules = productionScheduleService.findByExampleSort(specification, null);
            List<ProductionScheduleDto> productionScheduleDtos = productionSchedules.stream()
                    .map(productionSchedule -> toLazyDto(productionSchedule))
                    .collect(Collectors.toList());
            // 补充高低阻字段
            for (ProductionScheduleDto dto : productionScheduleDtos) {
                NewProductModel model = newProductModelService.findByCode(dto.getProductModelCode());
                if (!ObjectUtils.isEmpty(model)){
                    dto.setResistanceType(model.getResistanceType());
                }
            }
            EasyExcelUtils.write(response, ProductionScheduleDto.class, "导出单晶生成工单列表", "导出单晶生成工单列表", productionScheduleDtos);
        } catch (IOException e) {
            throw new RuntimeException("导出单晶生成工单列表失败，错误信息：" + e.getMessage());
        }
    }

    public ProductionScheduleDto toLazyDto(ProductionSchedule entity) {
        ProductionScheduleDto dto = modelMapper.map(entity, ProductionScheduleDto.class);
        dto.setCapacityInfoProductRank(Optional.ofNullable(entity).map(ProductionSchedule::getProductModel).map(ProductModel::getProductGrade).orElse(""));
        return dto;
    }

    public ProductionScheduleDto toEagerDto(ProductionSchedule entity) {
        ProductionScheduleDto dto = modelMapper.map(entity, ProductionScheduleDto.class);
        return dto;
    }

    public ProductionSchedule fromDto(ProductionScheduleDto dto) {
        return modelMapper.map(dto, ProductionSchedule.class);
    }


}
