package com.prolog.eis.service.stationOutbound.impl;


import com.prolog.eis.dto.eis4.*;
import com.prolog.eis.service.stationOutbound.StationObCacheDispatchService;
import com.prolog.eis.service.stationOutbound.StationObDispatchService;
import com.prolog.eis.service.stationOutbound.StationObNoTaskDispatchService;
import com.prolog.eis.service.stationOutbound.StationObTaskDispatchService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class StationObDispatchServiceImpl implements StationObDispatchService {
    private final StationObTaskDispatchService stationObTaskDispatchService;
    private final StationObCacheDispatchService stationObCacheDispatchService;
    private final StationObNoTaskDispatchService stationObNoTaskDispatchService;

    @Override
    public List<StationOBCarryTaskDto> dispatch(StationOBDispatchDto stationOBDispatch) throws Exception {
        this.init(stationOBDispatch);
        this.checkStationOBDispatchData(stationOBDispatch);

        List<StationOBCarryTaskDto> obCarryTaskList = new ArrayList<>();

        List<StationOBCarryTaskDto> taskObCarryTaskList = stationObTaskDispatchService.dispatch(stationOBDispatch);
        obCarryTaskList.addAll(taskObCarryTaskList);

        List<StationOBCarryTaskDto> cacheObCarryTaskList = stationObCacheDispatchService.dispatch(stationOBDispatch);
        obCarryTaskList.addAll(cacheObCarryTaskList);

        List<StationOBCarryTaskDto> noTaskObCarryTaskList = stationObNoTaskDispatchService.dispatch(stationOBDispatch);
        obCarryTaskList.addAll(noTaskObCarryTaskList);

        this.printTask(obCarryTaskList);

        return obCarryTaskList;
    }

    private void checkStationOBDispatchData(StationOBDispatchDto stationOBDispatch) throws Exception {
        Map<String, String> areaContainerNoMap = new HashMap<>();
        for (StationOBAreaDto area : stationOBDispatch.getAreaList()) {
            for (StationOBAreaContainerDto container : area.getContainerList()) {
                if (areaContainerNoMap.containsKey(container.getContainerNo())) {
                    String otherAreaNo = areaContainerNoMap.get(container.getContainerNo());
                    throw new Exception("数据异常：容器【" + container.getContainerNo() + "】同时在区域【" + area.getAreaNo() + "】和区域【" + otherAreaNo + "】到位");
                }
                areaContainerNoMap.put(container.getContainerNo(), area.getAreaNo());
            }
        }
    }

    private void printTask(List<StationOBCarryTaskDto> obCarryTaskList) {
        if (obCarryTaskList.size() == 0) {
            System.out.println("本次存储区到站任务调度：无任务下发");
            return;
        }

        StringBuilder sb = new StringBuilder();
        for (StationOBCarryTaskDto task : obCarryTaskList) {
            sb.append("\n" + task.getContainerNo() + "：" + task.getSourceAreaNo() + " -> " + task.getTargetAreaNo());
        }
        System.out.println(String.format("本次存储区到站任务调度：%s\n", sb.toString()));
    }

    public void init(StationOBDispatchDto dispatchDto) throws Exception {
        if (dispatchDto.isInit()) {
            throw new Exception("StationOBDispatchDto：1个实例的初始化方法只允许调用1次！");
        }
        dispatchDto.setInit(true);

        if (dispatchDto.getAreaList() == null) {
            throw new Exception("StationOBDispatchDto的areaList集合为NULL");
        }

        this.initAreaMap(dispatchDto);
        this.initContainerMap(dispatchDto);

        for (StationOBAreaDto area : dispatchDto.getAreaList()) {
            this.initArea(dispatchDto, area);
        }

        for (StationOBContainerDto container : dispatchDto.getContainerList()) {
            for (StationOBAreaDto area : dispatchDto.getAreaList()) {
                for (StationOBAreaContainerDto areaContainer : area.getContainerList()) {
                    areaContainer.setAreaNo(area.getAreaNo());

                    if (areaContainer.getContainerNo().equals(container.getContainerNo())) {
                        container.setAreaNo(area.getAreaNo());
                        container.setAreaPriority(area.getPriority());
                        container.setX(areaContainer.getX());
                        container.setY(areaContainer.getY());
                    }
                }
            }
        }
    }

    private void initAreaMap(StationOBDispatchDto dispatchDto) throws Exception {
        for (StationOBAreaDto area : dispatchDto.getAreaList()) {
            if (area.getAreaNo() == null)
                throw new Exception("StationOBAreaDto的areaNo为NULL");

            if (dispatchDto.getAreaMap().containsKey(area.getAreaNo()))
                throw new Exception("重复的areaNo：" + area.getAreaNo());

            dispatchDto.getAreaMap().put(area.getAreaNo(), area);
        }
    }

    private void initContainerMap(StationOBDispatchDto dispatchDto) throws Exception {
        for (StationOBContainerDto container : dispatchDto.getContainerList()) {
            if (container.getContainerNo() == null)
                throw new Exception("StationOBContainerDto的containerNo为NULL");

            if (dispatchDto.getTaskContainerMap().containsKey(container.getContainerNo()))
                throw new Exception("重复的containerNo：" + container.getContainerNo());

            dispatchDto.getTaskContainerMap().put(container.getContainerNo(), container);
        }
    }

    private void initArea(StationOBDispatchDto dispatchDto, StationOBAreaDto area) throws Exception {
        for (String taskSourceAreaNo : area.getTaskSourceAreaNoList()) {
            if (!dispatchDto.getAreaMap().containsKey(taskSourceAreaNo)) {
                throw new Exception("【" + taskSourceAreaNo + "】找不到对应的StationOBAreaDto");
            }
            area.getTaskSourceAreaList().add(dispatchDto.getAreaMap().get(taskSourceAreaNo));
        }

        for (StationOBAreaContainerDto container : area.getContainerList()) {
            if (dispatchDto.getTaskContainerMap().containsKey(container.getContainerNo())) {
                area.getTaskContainerList().add(dispatchDto.getTaskContainerMap().get(container.getContainerNo()));
            } else {
                area.getNoTaskContainerNoList().add(container);
            }
        }
    }
}
