package easydo.technology.service.impl;

import easydo.technology.components.JdbcClient;
import easydo.technology.enums.MESEnum;
import easydo.technology.exception.BizException;
import easydo.technology.model.ProcessRoute;
import easydo.technology.model.ProductBom;
import easydo.technology.model.ProductMaterial;
import easydo.technology.model.QualityInspectProgram;
import easydo.technology.service.FlowNoService;
import easydo.technology.service.ProductBomService;
import easydo.technology.utils.SecurityUtils;
import easydo.technology.utils.StringUtil;
import org.springframework.stereotype.Service;

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

@Service
public class ProductBomServiceImpl implements ProductBomService {

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

    @Override
    public Object getPage(Map<String, Object> map) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            // 确保分页查询只返回顶级数据（对齐业务逻辑：顶级 parent_id 为 0）
            if (map != null && !map.containsKey("parentId")) {
                map.put("parentId", "0");
            }
            Map<String, Object> recordsPage = jdbcClient.getJdbcPage(map, ProductBom.class, connection);
            List<ProductBom> records = (List<ProductBom>) recordsPage.get("records");
            for (ProductBom model : records) {
                fillBomMetadata(model, connection);
            }
            return recordsPage;
        } finally {
            connection.close();
        }
    }

    @Override
    public Object getChildrenList(Map<String, Object> map) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            List<ProductBom> detailList = jdbcClient.getJdbcList(map, ProductBom.class, connection);
            for (ProductBom bomDetail : detailList) {
                fillBomMetadata(bomDetail, connection);
            }
            return detailList;
        } finally {
            connection.close();
        }
    }

    private void fillBomMetadata(ProductBom model, Connection connection) throws Exception {
        // 1. Backfill Material
        ProductMaterial material = new ProductMaterial();
        material.setCode(model.getMaterialCode());
        material.setTenantId(model.getTenantId());
        material = jdbcClient.getJdbcModel(material, connection);
        model.setMaterial(material);

        // 2. Check for children
        ProductBom param = new ProductBom();
        param.setParentId(model.getId());
        int count = jdbcClient.getJdbcCount(param, connection);
        model.setIsHaveChildren(count > 0);

        // 3. Backfill RouteName (Align with Go)
        if (StringUtil.isNotEmpty(model.getRouteId())) {
            ProcessRoute route = new ProcessRoute();
            route.setId(model.getRouteId());
            route = jdbcClient.getJdbcModelById(route, connection);
            if (route != null) {
                model.setRouteName(route.getName());
                
                // 4. Backfill InspectProgramId and InspectProgramName from ProcessRoute
                if (StringUtil.isNotEmpty(route.getInspectProgramId())) {
                    model.setInspectProgramId(route.getInspectProgramId());
                    
                    QualityInspectProgram inspectProgram = new QualityInspectProgram();
                    inspectProgram.setId(route.getInspectProgramId());
                    inspectProgram = jdbcClient.getJdbcModelById(inspectProgram, connection);
                    if (inspectProgram != null) {
                        model.setInspectProgramName(inspectProgram.getName());
                    }
                }
            }
        }
    }

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

            // 1. 顶级防重校验：仅在“新建”顶级BOM时触发
            if (StringUtil.isEmpty(model.getId()) && "0".equals(model.getParentId())) {
                ProductBom existParam = new ProductBom();
                existParam.setMaterialCode(model.getMaterialCode());
                existParam.setParentId(model.getParentId());
                existParam.setTenantId(model.getTenantId());
                int count = jdbcClient.getJdbcCount(existParam, connection);
                if (count > 0) {
                    throw new BizException("该物料已经添加过BOM,请勿重复添加");
                }
            }

            // 2. 保存或更新主节点
            if ("0".equals(model.getParentId())) {
                model.setStatus(MESEnum.PROCESS_OF_STATUS_ENABLE.getValue());
            } else {
                model.setStatus(null);
            }

            if (StringUtil.isEmpty(model.getId())) {
                model.setCreateId(userId);
                model.setBomCode(flowNoService.generateProductBomCode(model, connection));
                jdbcClient.jdbcInsert(model, connection);
            } else {
                model.setUpdateId(userId);
                jdbcClient.jdbcUpdateById(model, connection);
            }

            // 3. 差量同步子项 (childrenList)
            List<ProductBom> incomingChildren = model.getChildrenList();
            if (incomingChildren != null) {
                // 获取数据库中现有的子项
                ProductBom param = new ProductBom();
                param.setParentId(model.getId());
                List<ProductBom> existingList = jdbcClient.getJdbcList(param, connection);
                List<String> removeIdList = existingList.stream().map(ProductBom::getId).collect(Collectors.toList());

                List<ProductBom> insertList = incomingChildren.stream().filter(item -> StringUtil.isEmpty(item.getId())).collect(Collectors.toList());
                List<ProductBom> updateList = incomingChildren.stream().filter(item -> StringUtil.isNotEmpty(item.getId())).collect(Collectors.toList());
                
                List<String> updateIdList = updateList.stream().map(ProductBom::getId).collect(Collectors.toList());
                removeIdList.removeAll(updateIdList);

                // 执行插入
                for (ProductBom child : insertList) {
                    child.setParentId(model.getId());
                    child.setBomCode(model.getBomCode());
                    child.setTenantId(model.getTenantId());
                    child.setCreateId(userId);
                    // 子项不是顶级，不增加状态
                    child.setStatus(null);
                    jdbcClient.jdbcInsert(child, connection);
                }
                // 执行更新
                for (ProductBom child : updateList) {
                    child.setUpdateId(userId);
                    // 确保子项也同步父项的编号和租户
                    child.setBomCode(model.getBomCode());
                    child.setTenantId(model.getTenantId());
                    // 子项不是顶级，不修改状态
                    child.setStatus(null);
                    jdbcClient.jdbcUpdateById(child, connection);
                }
                // 执行删除（物理删除不再存在于列表中的项）
                for (String id : removeIdList) {
                    ProductBom toRemove = new ProductBom();
                    toRemove.setId(id);
                    jdbcClient.jdbcRemoveById(toRemove, connection);
                }
            }

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

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

            model.setUpdateId(userId);
            jdbcClient.jdbcUpdateById(model, connection);

            List<ProductBom> incomingChildren = model.getChildrenList();
            if (incomingChildren != null) {
                // Get existing children to diff
                ProductBom param = new ProductBom();
                param.setParentId(model.getId());
                List<ProductBom> existingList = jdbcClient.getJdbcList(param, connection);
                List<String> removeIdList = existingList.stream().map(ProductBom::getId).collect(Collectors.toList());

                List<ProductBom> insertList = incomingChildren.stream().filter(item -> StringUtil.isEmpty(item.getId())).collect(Collectors.toList());
                List<ProductBom> updateList = incomingChildren.stream().filter(item -> StringUtil.isNotEmpty(item.getId())).collect(Collectors.toList());
                
                List<String> updateIdList = updateList.stream().map(ProductBom::getId).collect(Collectors.toList());
                removeIdList.removeAll(updateIdList);

                for (ProductBom child : insertList) {
                    child.setParentId(model.getId());
                    child.setBomCode(model.getBomCode());
                    child.setTenantId(model.getTenantId());
                    child.setCreateId(userId);
                    jdbcClient.jdbcInsert(child, connection);
                }
                for (ProductBom child : updateList) {
                    child.setUpdateId(userId);
                    jdbcClient.jdbcUpdateById(child, connection);
                }
                for (String id : removeIdList) {
                    ProductBom toRemove = new ProductBom();
                    toRemove.setId(id);
                    jdbcClient.jdbcRemoveById(toRemove, connection);
                }
            }

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

    @Override
    public Object remove(ProductBom model) throws Exception {
        jdbcClient.jdbcRemoveById(model);
        return model;
    }
}

