package easydo.technology.service.impl;

import easydo.technology.components.JdbcClient;
import easydo.technology.enums.MESEnum;
import easydo.technology.model.*;
import easydo.technology.system.model.SysUser;
import easydo.technology.service.FlowNoService;
import easydo.technology.service.ProcessRouteService;
import easydo.technology.utils.SecurityUtils;
import easydo.technology.utils.StringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ProcessRouteServiceImpl implements ProcessRouteService {

    @Resource
    JdbcClient jdbcClient;
    @Resource
    DataSource dataSource;
    @Resource
    FlowNoService flowNoService;

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Object getList(Map<String, Object> map) throws Exception {
        List<ProcessRoute> list = jdbcClient.getJdbcList(map, ProcessRoute.class);
        Connection connection = dataSource.getConnection();
        try {
            for (ProcessRoute model : list) {
                fillRouteDetails(model, connection);
            }
        } finally {
            connection.close();
        }
        return list;
    }

    @Override
    public Object getPage(Map<String, Object> map) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            Map<String, Object> recordsPage = jdbcClient.getJdbcPage(map, ProcessRoute.class, connection);
            List<ProcessRoute> records = (List<ProcessRoute>) recordsPage.get("records");
            for (ProcessRoute model : records) {
                fillRouteDetails(model, connection);
            }
            return recordsPage;
        } finally {
            connection.close();
        }
    }

    private void fillRouteDetails(ProcessRoute model, Connection connection) throws Exception {
        // 1. 回填明细与工序
        ProcessRouteDetail routeDetail = new ProcessRouteDetail();
        routeDetail.setRouteId(model.getId());
        List<ProcessRouteDetail> routeDetailList = jdbcClient.getJdbcList(routeDetail, connection);
        for (ProcessRouteDetail detail : routeDetailList) {
            ProcessStage stage = new ProcessStage();
            stage.setId(detail.getStageId());
            stage = jdbcClient.getJdbcModelById(stage, connection);
            detail.setStage(stage);

            // 补齐逻辑：解析 device_list 并回显名称数组
            if (StringUtil.isNotEmpty(detail.getDeviceList())) {
                try {
                    List<String> deviceIds = objectMapper.readValue(detail.getDeviceList(), new TypeReference<List<String>>() {});
                    List<String> deviceNames = new ArrayList<>();
                    for (String deviceId : deviceIds) {
                        Device device = new Device();
                        device.setId(deviceId);
                        device = jdbcClient.getJdbcModelById(device, connection);
                        deviceNames.add(device != null ? device.getName() : "未知设备");
                    }
                    detail.setDeviceNameList(deviceNames);
                } catch (Exception e) {
                    // 忽略解析异常
                }
            }
        }
        model.setDetailList(routeDetailList);

        // 2. 回填附件
        jdbcClient.getMinioFile(model, connection);

        // 3. 回填历史标记
        ProcessRoute child = new ProcessRoute();
        child.setParentId(model.getId());
        int count = jdbcClient.getJdbcCount(child, connection);
        model.setIsHaveHistory(count > 0);

        // 4. 回填检验方案对象
        if (StringUtil.isNotEmpty(model.getInspectProgramId())) {
            QualityInspectProgram inspectProgram = new QualityInspectProgram();
            inspectProgram.setId(model.getInspectProgramId());
            inspectProgram = jdbcClient.getJdbcModelById(inspectProgram, connection);

            if (inspectProgram != null) {
                if (inspectProgram.getInspectUserId() != null) {
                    SysUser inspectUser = new SysUser();
                    inspectUser.setId(inspectProgram.getInspectUserId());
                    inspectUser = jdbcClient.getJdbcModelById(inspectUser, connection);
                    if (inspectUser != null) {
                        inspectProgram.setInspectUserName(inspectUser.getNickName());
                    }
                }

                if (inspectProgram.getReviewUserId() != null) {
                    SysUser reviewUser = new SysUser();
                    reviewUser.setId(inspectProgram.getReviewUserId());
                    reviewUser = jdbcClient.getJdbcModelById(reviewUser, connection);
                    if (reviewUser != null) {
                        inspectProgram.setReviewUserName(reviewUser.getNickName());
                    }
                }

                // 补齐质检方案自身的附件回填（质检方案可能已被删除或 id 为空，避免 NPE）
                try {
                    if (StringUtil.isNotEmpty(inspectProgram.getId())) {
                        jdbcClient.getMinioFile(inspectProgram, connection);
                    }
                } catch (Exception ignore) {
                    // 忽略附件回填异常
                }
            }

            model.setInspectProgram(inspectProgram);
        }
    }

    @Override
    public Object save(ProcessRoute model) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            connection.setAutoCommit(false);
            model.setCreateId(SecurityUtils.getCurrentUserId());
            model.setCode(flowNoService.generateProcessRouteCode(model, connection));
            model.setParentId("0");
            model.setStatus(MESEnum.PROCESS_OF_STATUS_ENABLE.getValue());
            jdbcClient.jdbcInsert(model, connection);

            List<ProcessRouteDetail> detailList = model.getDetailList();
            if (detailList != null) {
                for (ProcessRouteDetail detail : detailList) {
                    detail.setRouteId(model.getId());
                    jdbcClient.jdbcInsert(detail, connection);
                }
            }
            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw e;
        } finally {
            connection.close();
        }
    }

    @Override
    public Object update(ProcessRoute model) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            connection.setAutoCommit(false);
            model.setUpdateId(SecurityUtils.getCurrentUserId());
            jdbcClient.jdbcUpdateById(model, connection);

            ProcessRouteDetail routeDetail = new ProcessRouteDetail();
            routeDetail.setRouteId(model.getId());
            jdbcClient.jdbcRemove(routeDetail, connection);

            List<ProcessRouteDetail> detailList = model.getDetailList();
            if (detailList != null) {
                for (ProcessRouteDetail detail : detailList) {
                    detail.setRouteId(model.getId());
                    jdbcClient.jdbcInsert(detail, connection);
                }
            }
            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw e;
        } finally {
            connection.close();
        }
    }

    @Override
    public Object remove(ProcessRoute model) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            connection.setAutoCommit(false);
            jdbcClient.jdbcRemoveById(model, connection);

            ProcessRouteDetail routeDetail = new ProcessRouteDetail();
            routeDetail.setRouteId(model.getId());
            jdbcClient.jdbcRemove(routeDetail, connection);

            ProcessRoute history = new ProcessRoute();
            history.setParentId(model.getId());
            List<ProcessRoute> historyList = jdbcClient.getJdbcList(history, connection);
            for (ProcessRoute hismodel : historyList) {
                jdbcClient.jdbcRemoveById(hismodel, connection);
                ProcessRouteDetail routeHisDetail = new ProcessRouteDetail();
                routeHisDetail.setRouteId(hismodel.getId());
                jdbcClient.jdbcRemove(routeHisDetail, connection);
            }

            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw e;
        } finally {
            connection.close();
        }
    }

    @Override
    public Object upgrade(ProcessRoute model) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            connection.setAutoCommit(false);
            Long userId = SecurityUtils.getCurrentUserId();

            // 对齐 Go 执行顺序：先插入新版本，再归档旧版本，再迁移历史链
            String oldId = model.getId();

            model.setCreateId(userId);
            model.setCode(flowNoService.generateProcessRouteCode(model, connection));
            model.setParentId("0");
            model.setId(UUID.randomUUID().toString());
            model.setStatus(MESEnum.PROCESS_OF_STATUS_ENABLE.getValue());
            jdbcClient.jdbcInsert(model, connection);

            ProcessRoute existRoute = new ProcessRoute();
            existRoute.setId(oldId);
            existRoute.setParentId(model.getId());
            existRoute.setStatus(MESEnum.PROCESS_OF_STATUS_DISABLE.getValue());
            existRoute.setUpdateId(userId);
            jdbcClient.jdbcUpdateById(existRoute, connection);

            ProcessRoute childrenRoute = new ProcessRoute();
            childrenRoute.setParentId(model.getId());
            childrenRoute.setUpdateId(userId);
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("parentId", oldId);
            jdbcClient.jdbcUpdate(childrenRoute, paramMap, connection);

            List<ProcessRouteDetail> detailList = model.getDetailList();
            if (detailList != null) {
                for (ProcessRouteDetail detail : detailList) {
                    detail.setRouteId(model.getId());
                    jdbcClient.jdbcInsert(detail, connection);
                }
            }
            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw e;
        } finally {
            connection.close();
        }
    }

    @Override
    public Object regrade(ProcessRoute model) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            connection.setAutoCommit(false);
            Long userId = SecurityUtils.getCurrentUserId();
            ProcessRoute children = new ProcessRoute();
            children.setParentId(model.getId());
            List<ProcessRoute> childrenList = jdbcClient.getJdbcList(children, connection);
            
            if (!childrenList.isEmpty()) {
                childrenList = childrenList.stream()
                    .sorted(Comparator.comparing(ProcessRoute::getCreateTime).reversed())
                    .collect(Collectors.toList());
                
                ProcessRoute child = childrenList.get(0);
                child.setParentId("0");
                child.setStatus(MESEnum.PROCESS_OF_STATUS_ENABLE.getValue());
                child.setUpdateId(userId);
                jdbcClient.jdbcUpdateById(child, connection);

                ProcessRoute childrenRoute = new ProcessRoute();
                childrenRoute.setParentId(child.getId());
                childrenRoute.setUpdateId(userId);
                Map<String, Object> paramMap = new HashMap<>();
                paramMap.put("parentId", model.getId());
                jdbcClient.jdbcUpdate(childrenRoute, paramMap, connection);

                jdbcClient.jdbcRemoveById(model, connection);

                ProcessRouteDetail routeDetail = new ProcessRouteDetail();
                routeDetail.setRouteId(model.getId());
                jdbcClient.jdbcRemove(routeDetail, connection);
            }
            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw e;
        } finally {
            connection.close();
        }
    }
}
