package cn.edu.whu.boot.common.utils.collection;

import cn.edu.whu.boot.allocation.services.TaskUserRoleService;
import cn.edu.whu.boot.collection.dto.Feature;
import cn.edu.whu.boot.collection.dto.GeometryType;
import cn.edu.whu.boot.common.domain.CommonConstant;
import cn.edu.whu.boot.common.domain.ResultMessage;
import cn.edu.whu.boot.xml.domain.Task;
import cn.edu.whu.boot.xml.domain.XmlEnity;
import com.alibaba.fastjson.JSON;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * 放置一些零散的方法
 */
public class OtherUtil{

    /**
     * 利用 HttpServletResponse 上传文件
     */
    public static String uploadFileByResponse(File file, HttpServletResponse response){
        if(file.exists()){
            try(InputStream inputStream = new FileInputStream(file);
                BufferedInputStream bis = new BufferedInputStream(inputStream);
                ServletOutputStream servletOutputStream = response.getOutputStream();
                BufferedOutputStream bos = new BufferedOutputStream(servletOutputStream)){
                byte[] buff = new byte[2048];
                // 根据 BufferedInputStream 里内容写入到 BufferedOutputStream 中
                int bytesRead;
                while(-1 != (bytesRead = bis.read(buff, 0, buff.length))){
                    bos.write(buff, 0, bytesRead);
                }
                bos.flush();
            } catch(final IOException e){
                return CommonConstant.FAILED;
            }
        }
        else{
            return CommonConstant.FAILED;
        }
        return CommonConstant.SUCCEED;
    }

    /**
     * 根据xmlEnity类的文件路径和其对应的MD5Code判断xml文件是否被更改
     */
    public static boolean checkXmlFileIsModified(XmlEnity xmlEnity){
        String filePath = xmlEnity.getFilePath();
        String fileMD5CodeOld = xmlEnity.getMd5Code();
        String fileMD5CodeNew = "";
        try{
            fileMD5CodeNew = EncryptUtils.getMd5ByFile(new File(filePath));
        }
        catch(Exception e){
            e.printStackTrace();
        }
        return !fileMD5CodeOld.equals(fileMD5CodeNew);
    }

    /**
     * 检查 List<Map<String,Object>> 的 size 值，只有 size 为 1 才返回 succeed
     */
    public static ResultMessage checkDataListGetByPolygonId(List<Map<String, Object>> rootTableDataList){
        if(rootTableDataList == null){
            return ResultMessage.failed("无数据，请核对");
        }
        if(rootTableDataList.size() == 1){
            return ResultMessage.success(null);
        }
        else{
            return ResultMessage.failed(null);
        }
    }

    /**
     * RouteLine、RoutePoint以及Draft类从安卓端上传的时间是"20190922161832763"，将其转换为"2019-09-22 16:18:32.763"
     */
    public static String changeTimeString(String timeString){
        return timeString.substring(0, 4) + "-" + timeString.substring(4, 6) + "-" + timeString.substring(6, 8) + " " + timeString.substring(8, 10) + ":" + timeString.substring(10, 12) + ":" + timeString.substring(12, 14) + "." + timeString.substring(14, timeString.length());
    }

    /**
     * 用于获取xml文件中<field>标签下含有<select>标签的key 和 value
     * 主要是用于网页端属性获取和统计决策中同时显示key 和 value，若单独显示key则不清楚含义
     */
//    public static Map<String, String> getSelectKeyValueMap(String xmlFilePath, String tableName, String fieldName) throws Exception{
//        Map<String, String> result = new HashMap<>();
//        Document document = new SAXBuilder().build(new File(xmlFilePath));
//        Element configElement = document.getRootElement();
//        Element tablesElement = configElement.getChild("tables");
//        List tableElementList = tablesElement.getChildren("table");
//
//        for(Object obj : tableElementList){
//            Element tableElement = (Element) obj;
//            if(tableElement.getAttributeValue("key").equals(tableName)){
//                List fieldElementList = tableElement.getChildren("field");
//                for(Object fieldObj : fieldElementList){
//                    Element fieldElement = (Element) fieldObj;
//                    if(fieldName.equals(fieldElement.getAttributeValue("key"))){
//                        // 如果<field>标签下有<select>标签
//                        result.putAll(addSelectKeyValueToMap(fieldElement));
//                    }
//                    // 如果<field>标签下有<group>标签
//                    if(fieldElement.getChildren("group").size() != 0){
//                        for(Object groupObj : fieldElement.getChildren("group")){
//                            Element groupElement = (Element) groupObj;
//                            result.putAll(addSelectKeyValueToMap(groupElement));
//                        }
//                    }
//                }
//            }
//        }
//        return result;
//    }
    /**
     * 用于获取xml文件中<field>标签下含有<select>标签的key 和 value
     * 主要是用于网页端属性获取和统计决策中同时显示key 和 value，若单独显示key则不清楚含义
     * 2025 7.28修正 <group> 级别未区分，导致 key 冲突或被覆盖
     */
    public static Map<String, String> getSelectKeyValueMap(String xmlFilePath, String tableName, String fieldName) throws Exception {
        Map<String, String> result = new LinkedHashMap<>(); // 保证顺序一致
        Document document = new SAXBuilder().build(new File(xmlFilePath));
        Element configElement = document.getRootElement();
        Element tablesElement = configElement.getChild("tables");
        List<?> tableElementList = tablesElement.getChildren("table");

        for (Object obj : tableElementList) {
            Element tableElement = (Element) obj;
            if (tableElement.getAttributeValue("key").equals(tableName)) {
                List<?> fieldElementList = tableElement.getChildren("field");
                for (Object fieldObj : fieldElementList) {
                    Element fieldElement = (Element) fieldObj;
                    if (fieldName.equals(fieldElement.getAttributeValue("key"))) {
                        // 添加 field 下的 <select>
                        result.putAll(addSelectKeyValueToMap(fieldElement));
                        // 如果 <group> 也有 <select>
                        for (Object groupElement : fieldElement.getChildren("group")) {
                            result.putAll(addSelectKeyValueToMap((Element) groupElement));
                        }
                        return result; // 找到目标字段就返回
                    }
                }
            }
        }
        return result;
    }

    /**
     * 如果Element下有<select>标签，则添加<select>标签下的Key 和 Value到Map中
     */
    private static Map<String, String> addSelectKeyValueToMap(Element element){
        Map<String, String> result = new HashMap<>();
        if(element.getChildren("select").size() != 0){
            for(Object selectObj : element.getChildren("select")){
                Element selectElement = (Element) selectObj;
                if(!result.containsKey(selectElement.getAttributeValue("key"))){
                    result.put(selectElement.getAttributeValue("key"), selectElement.getAttributeValue("value"));
                }
            }
        }
        return result;
    }

    /**
     * 在 Map 中根据value查询key，针对于key和value都唯一的Map
     */
    public static String getKeyByValue(Map<String, String> map, String obj){
        for(Map.Entry<String, String> entry : map.entrySet()){
            if(entry.getValue().equals(obj)){
                return entry.getKey();
            }
        }
        return null;
    }

    /**
     * 根据 Geohash 聚类得出的结果，组成一个FeatureCountList
     */
    public static List<Map<String, Object>> genFeatureCountList(List<Map<String, Object>> dataList){
        List<Map<String, Object>> result = new ArrayList<>();
        for(Map<String, Object> data : dataList){
            Map<String, Object> tempMap = new HashMap<>();
            Feature feature = new Feature();
            feature.setType(CommonConstant.FEATURE);
            feature.setGeometry(JSON.toJavaObject(JSON.parseObject(data.get(CommonConstant.GEOMETRY).toString()), GeometryType.class));
            tempMap.put("count", data.get(CommonConstant.DATACOUNT));
            tempMap.put("feature", feature);
            result.add(tempMap);
        }
        return result;
    }

    /**
     * 获取采集数据表中 status 字段的含义
     */
    public static String getStatusMeaning(int status){
        switch(status){
            case -1:
                return "审核未通过";
            case 0:
                return "分配未审核";
            case 1:
                return "采集未审核";
            case 2:
                return "审核已通过";
            default:
                return null;
        }
    }

    /**
     * ArcMap 的 ShpFile 中的 .dbf 存储地理数据的属性信息，以 dBase IV 的数据表格式存储!
     * .dbf 文件头结构的第 29 字节开始，长度为 1 字节的数据为 Language driver ID，映射关系如下：
     * 当 Language driver ID 为 0x4D 或 0x7A 时返回 GBK !
     * 其他情况返回 UTF-8 !
     */
    public static String getShpFileCodingByDbf(File dbfFile) throws IOException{
        RandomAccessFile randomAccessFile = new RandomAccessFile(dbfFile, "r");
        randomAccessFile.seek(29L);
        int result = randomAccessFile.read();
        randomAccessFile.close();
        if(result == -1){
            return null;
        }
        else if(result == 0x4D || result == 0x7A){
            return "GBK";
        }
        else{
            return "UTF-8";
        }
    }


    /**
     * 检查用户是否在任务中
     * @param task Task 对象
     * @param userId 用户id
     * @param taskUserRoleService 用于查询 Task 的人员
     */
    public static boolean isUserInTask(Task task, int userId, TaskUserRoleService taskUserRoleService){
        // 如果任务无需分配，那么所有人都在该任务中!!!
        if(task.getIsAllocationOptional() == Task.WITHOUT_ALLOCATION){
            return true;
        }

        Optional<Integer> workRoleOpt = taskUserRoleService.findWorkRoleByTaskIdAndUserId(task.getId(), userId);
        return workRoleOpt.isPresent();
    }
}
