package com.mvc.service;

import com.mvc.constant.BaseConstant;
import com.mvc.constant.DeviceType;
import com.mvc.dao.TUnitStructureMapper;
import com.mvc.entity.TUnitStructure;
import com.mvc.entity.TUnitStructureExample;
import com.mvc.model.StationAccModel;
import com.mvc.model.TUnitStructureModel;
import com.mvc.othermodel.GroupAndStationTree;
import com.mvc.service.taizhang.StationAccService;
import com.mvc.utils.PoiUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class TUnitStructureService {

    @Resource
    private TUnitStructureMapper tUnitStructureMapper;

    @Resource
    private StationAccService stationAccService;

    public List<TUnitStructureModel> findAllTUnitStructureByUnitCode(String unitCode) {
        TUnitStructureExample example = new TUnitStructureExample();
        TUnitStructureExample.Criteria criteria = example.createCriteria();
        criteria.andUnitCodeEqualTo(unitCode);
        List<TUnitStructureModel> resList = selectByExample(example);
        return resList;
    }

    private List<TUnitStructureModel> selectByExample(TUnitStructureExample example) {
        List<TUnitStructure> tUnitStructures = tUnitStructureMapper.selectByExample(example);
        List<TUnitStructureModel> resList = new ArrayList<>();
        for (TUnitStructure tUnitStructure : tUnitStructures) {
            TUnitStructureModel model = new TUnitStructureModel();
            BeanUtils.copyProperties(tUnitStructure, model);
            resList.add(model);
        }
        return resList;
    }

    /**
     * 根据字典类型和key获取对象
     *
     * @param dicType
     * @return
     */
    public TUnitStructureModel findATUnitStructureModelByDicTypeAndKey(String dicType, String dicKey) {
        if (StringUtils.isEmpty(dicType) || StringUtils.isEmpty(dicKey)) return null;
        TUnitStructureExample example = new TUnitStructureExample();
        TUnitStructureExample.Criteria criteria = example.createCriteria();
        List<TUnitStructure> tUnitStructures = tUnitStructureMapper.selectByExample(example);
        if (tUnitStructures != null && tUnitStructures.size() > 0) {
            TUnitStructureModel model = new TUnitStructureModel();
            BeanUtils.copyProperties(tUnitStructures.get(0), model);
            return model;
        }
        return null;
    }

    public TUnitStructureModel saveTUnitStructure(TUnitStructureModel model) {
        model.setCreateTime(new Date());
        TUnitStructure unitStructure = new TUnitStructure();
        BeanUtils.copyProperties(model, unitStructure);
        int insert = tUnitStructureMapper.insert(unitStructure);
        model.setId(unitStructure.getId());
        return model;
    }

    public TUnitStructureModel updateTUnitStructure(TUnitStructureModel model) {
        TUnitStructure TUnitStructure = tUnitStructureMapper.selectByPrimaryKey(model.getId());
        BeanUtils.copyProperties(model, TUnitStructure);
        int i = tUnitStructureMapper.updateByPrimaryKey(TUnitStructure);
        return model;
    }

    public int deleteTUnitStructure(int id) {
        int i = tUnitStructureMapper.deleteByPrimaryKey(id);
        return i;
    }

    public List<GroupAndStationTree> findGroupAndStationTreeByUnitCode(String unitCode) {
        List<GroupAndStationTree> treeList = new ArrayList<>();
        List<TUnitStructureModel> unitStructureList = findAllTUnitStructureByUnitCode(unitCode);
        List<StationAccModel> stationAccModels = stationAccService.findStationAccByUnitCode(unitCode);
        Map<Integer, List<StationAccModel>> stationAccModelMap = stationAccModels.stream()
                .filter(stationAccModel -> stationAccModel.getUnitStructureId() != null)
                .collect(Collectors.groupingBy(StationAccModel::getUnitStructureId));

        for (TUnitStructureModel unitStructure : unitStructureList) {
            GroupAndStationTree tree = new GroupAndStationTree(unitStructure);
            treeList.add(tree);
            //下面有站点
            if (stationAccModelMap.containsKey(unitStructure.getId())) {
                for (StationAccModel stationAcc : stationAccModelMap.get(unitStructure.getId())) {
                    GroupAndStationTree stationTree = new GroupAndStationTree(stationAcc);
                    stationTree.setParentcode(unitStructure.getNodeCode());
                    stationTree.setLabel(stationAcc.getStationFullName());
                    treeList.add(stationTree);
                }
                tree.setType("2");//2表示下一级是站点
            }
        }
        return treeList;
    }

    public String importUnitStructureData(MultipartFile file, String unitCode, String createMan) {
        StringBuilder builder = new StringBuilder();
        try {
            List<Map<Integer, String>> list = readUnitStructureExcel(file);

            if (list == null) {
                return "表格格式异常(缺少关键列或总列数不符合要求)";
            } else if (list.isEmpty()) {
                return "未读数到有效数据";
            }

            List<TUnitStructureModel> currentModelList = findAllTUnitStructureByUnitCode(unitCode);

            int num = 0;
            for (Map<Integer, String> map : list) {
                if(!map.containsKey(1)||StringUtils.isEmpty(map.get(1))){//不存在第一列或内容为空,跳过
                    continue;
                }
                String info = dealUnitStructureRecord(map, currentModelList, unitCode, createMan);
                builder.append(info);
                builder.append(BaseConstant.HTML_NEW_LINE);
                num++;
            }
            builder.insert(0, BaseConstant.HTML_NEW_LINE);
            builder.insert(0, "条记录");
            builder.insert(0, num);
            builder.insert(0, "共处理：");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return builder.toString();
    }

    /**
     * 处理导入的单位结构记录
     *
     * @param map
     * @param currentModelList
     * @param unitCode
     * @param createMan
     */
    private String dealUnitStructureRecord(Map<Integer, String> map, List<TUnitStructureModel> currentModelList, String unitCode, String createMan) {
        int level;
        int endIndex = map.size() - 3;//最右侧的固定列(站点名称、站点编码、设备类型)
        StringBuilder resBuilder = new StringBuilder();
        TUnitStructureModel parent = null;
        StringBuilder builder = new StringBuilder();
        for (int i = 1; i <= endIndex; i++) {//只遍历层级,不到站点信息
            level = i;
            String nodeName = map.get(i);
            builder.append(nodeName);
            int finalLevel = level;
            //当前等级已有的列表
            List<TUnitStructureModel> curLvList = currentModelList.stream().filter(s -> s.getNodeLevel() == finalLevel).collect(Collectors.toList());

            TUnitStructureModel finalParent = parent;
            Optional<TUnitStructureModel> optional = curLvList.stream().filter(s -> s.getNodeName().equals(nodeName)
                    && s.getNodeLevel() == finalLevel
                    && (finalParent == null ? true : s.getParentCode().equals(finalParent.getNodeCode()))).findFirst();
            if (optional.isPresent()) {
                parent = optional.get();
            } else {//有节点未匹配上
                TUnitStructureModel model = new TUnitStructureModel();

                model.setNodeName(nodeName);
                model.setUnitCode(unitCode);
                model.setCreateMan(createMan);
                model.setNodeLevel(level);
                model.setParentCode(level == 1 ? "00" : parent.getNodeCode());
                model.setNodeNum(getCurMaxNodeNum(curLvList, model.getParentCode()) + 1);

                if (level == 1) {//一个全新的节点
                    model.setParentCode("00");
                    model.setNodeCode(StringUtils.leftPad(model.getNodeNum() + "", 2, '0'));
                } else {//已有其它层级节点
                    model.setParentCode(parent.getNodeCode());
                    model.setNodeCode(parent.getNodeCode() + StringUtils.leftPad(model.getNodeNum() + "", 2, '0'));
                }

                TUnitStructureModel saveModel = saveTUnitStructure(model);
                currentModelList.add(saveModel);
                parent = saveModel;
            }
        }

        resBuilder.append("保存节点：");
        resBuilder.append(builder);
        resBuilder.append(", ");

        String stationName = map.get(endIndex + 1);
        String userDefinedCode = map.get(endIndex + 2);
        String deviceType = DeviceType.WATER_METER.getCode();
        if (map.containsKey(endIndex + 3)) {
            deviceType = map.get(endIndex + 3);
        }
        StationAccModel accModel = new StationAccModel();

        if (StringUtils.isNotEmpty(userDefinedCode)) {
            StationAccModel temp = stationAccService.findStationAccByUserDefinedCode(userDefinedCode);
            if (temp != null) {
                if (temp.getUnitCode().equals(unitCode)) {//本单位内已有此编码,执行更新
                    accModel = temp;
                }
            }
        }

        builder.append(stationName);
        accModel.setStationName(builder.toString());//全名称-为了不影响其它站点、APP、小程序的名称
        accModel.setUserDefinedCode(userDefinedCode);
        accModel.setStationFullName(stationName);//注意,这里是简称 字段名还需要修改
        accModel.setUnitStructureId(parent.getId());
        accModel.setDeviceType(deviceType);

        if (accModel.getId() == null) {
            accModel.setUnitCode(unitCode);
            accModel.setCreateMan(createMan);
            accModel.setMeterId("2");
            accModel.setDeviceSetupFlag("0");
            accModel.setUseFlag("0");
            accModel.setUnitCode(unitCode);
            accModel.setVisUnitCodes(unitCode);
            accModel.setCreateUnitCode(unitCode);
            accModel.setReviewFlag("0");
            stationAccService.saveStationAcc(accModel);
            resBuilder.append("新增站点台账：" + stationName);
        } else {
            stationAccService.updateStationAcc(accModel);
            resBuilder.append("更新站点台账：" + stationName);
        }
        return resBuilder.toString();
    }

    /**
     * 获取当前等级最大节点号
     *
     * @param curLvList
     * @param parentCode
     * @return
     */
    private int getCurMaxNodeNum(List<TUnitStructureModel> curLvList, String parentCode) {
        Optional<TUnitStructureModel> maxNodeNumRecord = curLvList.stream().filter(s -> s.getParentCode().equals(parentCode))
                .max(Comparator.comparingInt(TUnitStructureModel::getNodeNum));
        return maxNodeNumRecord.isPresent() ? maxNodeNumRecord.get().getNodeNum() : 0;
    }

    private static final String LAST_COL_NAME = "设备类型";//表格中最后一列的标题名

    /**
     * 读取台账模板表格
     *
     * @param file excel文件
     * @return
     */
    private List<Map<Integer, String>> readUnitStructureExcel(MultipartFile file) {
        List<Map<Integer, String>> list = new ArrayList<>();
        try {
            XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
            XSSFSheet sheet = workbook.getSheetAt(0);

            Iterator<Row> rowIterator = sheet.iterator();
            int lastColIndex = 20; // 最后一个有效列索引

            // 根据标题确定有效列数(以‘站点编码’为依据,作为硬性条件,因为层级设计是不限制的)
            Row row0 = rowIterator.next();
            for (int i = 1; i <= lastColIndex; i++) {
                Cell cell = row0.getCell(i);
                if (cell != null && PoiUtils.getCellValueAsString(cell).equals(LAST_COL_NAME)) {
                    lastColIndex = i + 1;
                    break;
                }
            }

            if (lastColIndex == 20 || lastColIndex < 5) { // 没有找到设备类型列或总列数小于5(序号列不算)
                return null;
            }

            // 记录合并区域的值
            Map<CellRangeAddress, String> mergedCellValues = new HashMap<>();

            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                Map<Integer, String> map = new HashMap<>();

                for (int colIndex = 1; colIndex < lastColIndex; colIndex++) {
                    Cell cell = row.getCell(colIndex);

                    boolean isMerged = false;
                    for (int k = 0; k < sheet.getNumMergedRegions(); k++) {
                        CellRangeAddress region = sheet.getMergedRegion(k);
                        if (region.isInRange(i, colIndex)) {//合并的单元格
                            isMerged = true;
                            int firstColumn = region.getFirstColumn();
                            int firstRow = region.getFirstRow();

                            // 获取合并区域的值
                            String mergedValue = mergedCellValues.computeIfAbsent(region, key -> {
                                Cell firstCell = sheet.getRow(firstRow).getCell(firstColumn);
                                return PoiUtils.getCellValueAsString(firstCell);
                            });


                            // 填充合并区域的值
                            map.put(colIndex, removeDecimalAndFraction(mergedValue));
                            colIndex = region.getLastColumn();
                            break;
                        }
                    }

                    //非合并单元格且第一级为空,跳过
                    if (!isMerged) {//未合并的单元格
                        map.put(colIndex, removeDecimalAndFraction(PoiUtils.getCellValueAsString(cell)));
                    }
                }
                if (!map.isEmpty()) {
                    list.add(map);
                }
            }

            workbook.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 去掉小数点及其后面数据
     * Excel中部分数字型文字可能会携带.0
     *
     * @param value
     * @return
     */
    private String removeDecimalAndFraction(String value) {
        int index = value.indexOf(".");
        if (index > -1) {//去掉小数点(有的字符串可能会被读取为数值类型,会有小数点)
            value = value.substring(0, index);
        }
        return value;
    }

    /**
     * 读取台账模板表格(未处理合并单元格版)
     *
     * @param file excel文件
     * @return
     */
     /* private List<Map<Integer, String>> readUnitStructureExcel2(MultipartFile file) {
        List<Map<Integer, String>> list = new ArrayList<>();
        try {
            XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
            XSSFSheet sheet = workbook.getSheetAt(0);

            Iterator<Row> rowIterator = sheet.iterator();
            int lastColIndex = 20;//最后一个有效列索引

            //根据标题确定有效列数(以‘站点编码’为依据,作为硬性条件,因为层级设计是不限制的)
            Row row0 = rowIterator.next();
            for (int i = 1; i <= lastColIndex; i++) {
                Cell cell = row0.getCell(i);
                if (cell != null && PoiUtils.getCellValueAsString(cell).equals(LAST_COL_NAME)) {
                    lastColIndex = i + 1;
                    break;
                }
            }

            if (lastColIndex == 20 || lastColIndex < 5) {//没有找到设备类型列或总列数小于5(序号列不算)
                return null;
            }

            while (rowIterator.hasNext()) {
                Row row = rowIterator.next();
                Map<Integer, String> map = new java.util.HashMap<>();
                //(序号,一级,二级,三级,.....N级,站点名称,站点编码) **:表格结构,理论层级不限制,末尾两列,必须是站点名称和站点编码
                for (int colIndex = 1; colIndex < lastColIndex; colIndex++) {//
                    Cell cell = row.getCell(colIndex);
                    //单元格无值也要与其它列对齐(因为模板允许部分站点层级不够时可为空)
                    String value = cell == null ? "" : PoiUtils.getCellValueAsString(cell);
                    int index = value.indexOf(".");
                    if (index > -1) {//去掉小数点(有的字符串可能会被读取为数值类型,会有小数点)
                        value = value.substring(0, index);
                    }
                    if (colIndex == 1 && value.equals("")) {//一级无内容,跳过
                        break;
                    }
                    map.put(colIndex, value);
                }
                if (!map.isEmpty()) {
                    list.add(map);
                }
            }
            workbook.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }*/
}
