package com.usky.fire.service.util;

//import com.baomidou.mybatisplus.core.toolkit.StringUtils;

import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.usky.common.core.util.HttpUtils;
import com.usky.fire.service.vo.LocateInfo;
import com.usky.fire.service.vo.PatrolInspectionAreaVo;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class OnlineMethod {

    public static Date transferString2Date(String s) {
        Date date = new Date();
        try {
            date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s);
        } catch (ParseException e) {
            //LOGGER.error("时间转换错误, string = {}", s, e);
        }
        return date;
    }

    /**
     * 默认地球半径
     */
    private static double EARTH_RADIUS = 6371000;//赤道半径(单位m)

    /**
     * 转化为弧度(rad)
     * */
    private static double rad(double d)
    {
        return d * Math.PI / 180.0;
    }
    /**
     * @param lon1 第一点的精度
     * @param lat1 第一点的纬度
     * @param lon2 第二点的精度
     * @param lat2 第二点的纬度
     * @return 返回的距离，单位m
     * */
    public static double GetDistance(double lon1,double lat1,double lon2, double lat2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lon1) - rad(lon2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000) / 10000;
        return s;
    }

    /**
     * 计算中心经纬度与目标经纬度的距离（米）
     *
     * @param centerLon 中心精度
     * @param centerLat 中心纬度
     * @param targetLon 需要计算的精度
     * @param targetLat 需要计算的纬度
     * @return 米
     */
    public static double distance(double centerLon, double centerLat, double targetLon, double targetLat) {
        double jl_jd = 102834.74258026089786013677476285;// 每经度单位米;
        double jl_wd = 111712.69150641055729984301412873;// 每纬度单位米;
        double b = Math.abs((centerLat - targetLat) * jl_jd);
        double a = Math.abs((centerLon - targetLon) * jl_wd);
        return Math.sqrt((a * a + b * b));
    }


    public static String getAlarmType(String value, Integer deviceType) {
        String alarmType = null;
        switch (value) {
            case "火警":
                alarmType = "2";
                break;
            case "故障":
                if (deviceType == 1) {
                    alarmType = "4";
                } else if (deviceType == 2) {
                    alarmType = "WP3";
                } else if (deviceType == 5) {
                    alarmType = "LL3";
                } else if (deviceType == 7) {
                    alarmType = "y05";
                }
                break;
            case "监管":
                alarmType = "16";
                break;
            case "正常/报警撤销":
                alarmType = "EF0";
                break;
            case "欠压报警":
                alarmType = "EF1";
                break;
            case "过压报警":
                alarmType = "EF2";
                break;
            case "过流报警":
                alarmType = "EF3";
                break;
            case "漏电报警":
                alarmType = "EF4";
                break;
            case "温度1超高报警":
                alarmType = "EF5";
                break;
            case "温度2超高报警":
                alarmType = "EF6";
                break;
            case "温度3超高报警":
                alarmType = "EF7";
                break;
            case "温度4超高报警":
                alarmType = "EF8";
                break;
            case "离线":
                if (deviceType == 2) {
                    alarmType = "WP4";
                } else if (deviceType == 7) {
                    alarmType = "EF9";
                }
                break;
            case "正常":
                if (deviceType == 2) {
                    alarmType = "WP0";
                } else if (deviceType == 5) {
                    alarmType = "LL0";
                }
                break;
            case "低压":
                if (deviceType == 2) {
                    alarmType = "WP1";
                } else if (deviceType == 3) {
                    alarmType = "y04";
                }
                break;
            case "高压":
                alarmType = "WP2";
                break;
            case "低水位":
                alarmType = "LL1";
                break;
            case "高水位":
                alarmType = "LL2";
                break;
            case "报警":
                alarmType = "y01";
                break;
            case "报警静音":
                alarmType = "y02";
                break;
            case "保留":
                alarmType = "y03";
                break;
            case "火灾报警":
                alarmType = "y07";
                break;
            case "温度报警":
                alarmType = "y08";
                break;
            case "烟感电量低":
                alarmType = "y09";
                break;
            case "防拆报警":
                alarmType = "y10";
                break;
            case "发射电路故障":
                alarmType = "y11";
                break;
            case "设备自检":
                alarmType = "y12";
                break;
            default:
                alarmType = value;
        }
        return alarmType;
    }

    /**
     * 1.地址转换为经纬度
     *
     * @param address 地址
     * @return 经纬度
     */
    private static final String GOULD_KEY = "2761d6ab4784b2f1de57a787f18c0e46";

    public static List<LocateInfo> getLonLat(String address) {
        List<LocateInfo> locateInfos = new ArrayList<>();
        try {
            // 返回输入地址address的经纬度信息, 格式是 经度,纬度
            String encode = URLEncoder.encode(address, "UTF-8");
            String queryUrl = "http://restapi.amap.com/v3/geocode/geo?" + "key=" + GOULD_KEY + "&address=" + encode + "&batch=true";
            String queryResult = getResponse(queryUrl);
            JsonNode arrNode = new ObjectMapper().readTree(queryResult).get("geocodes");
            if (arrNode.isArray()) {
                for (JsonNode objNode : arrNode) {
                    LocateInfo locateInfo = new LocateInfo();
                    String location = objNode.get("location").asText();
                    if (StringUtils.isNotBlank(location) && !"[]".equals(location)) {
                        String[] locations = StringUtils.split(objNode.get("location").asText(), ",");
                        locateInfo.setLongitude(Double.parseDouble(locations[0]));
                        locateInfo.setLatitude(Double.parseDouble(locations[1]));
                        locateInfo.setDistrict(objNode.get("district").asText());
                        locateInfo.setStreet(objNode.get("street").asText());
                    } else {
                        locateInfo.setLongitude(0.00);
                        locateInfo.setLatitude(0.00);
                        locateInfo.setDistrict("");
                        locateInfo.setStreet("");
                    }
                    locateInfos.add(locateInfo);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return locateInfos;
    }


    public static String getStreetTown(String location) {
        String streetTown = null;
        try {
            // 返回输入地址address的经纬度信息, 格式是 经度,纬度
            String encode = URLEncoder.encode(location, "UTF-8");
            String queryUrl = "http://restapi.amap.com/v3/geocode/regeo?" + "key=" + GOULD_KEY + "&location=" + encode + "";
            String queryResult = getResponse(queryUrl);
            JsonNode arrNode = new ObjectMapper().readTree(queryResult).get("regeocode");
            JsonNode addressComponent = arrNode.get("addressComponent");
            streetTown = addressComponent.get("township").toString();
            streetTown = streetTown.replace("\"", "");
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return streetTown;
    }

    /**
     * 3.发送请求
     *
     * @param serverUrl 请求地址
     */
    private static String getResponse(String serverUrl) {
        // 用JAVA发起http请求，并返回json格式的结果
        String result = "";
        try {
            result = HttpUtils.get(serverUrl, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 差集(基于java8新特性)优化解法2 适用于大数据量
     * 求List1中有的但是List2中没有的元素
     */
    public static List<String> subList2(List<String> list1, List<String> list2) {
        Map<String, String> tempMap = list2.parallelStream().collect(Collectors.toMap(Function.identity(), Function.identity(), (oldData, newData) -> newData));
        return list1.parallelStream().filter(str -> {
            return !tempMap.containsKey(str);
        }).collect(Collectors.toList());
    }

    /**
     * 差集(基于常规解法）优化解法1 适用于中等数据量
     * 求List1中有的但是List2中没有的元素
     * 空间换时间降低时间复杂度
     * 时间复杂度O(Max(list1.size(),list2.size()))
     */
    public static List<String> subList1(List<String> list1, List<String> list2) {
        //空间换时间 降低时间复杂度
        Map<String, String> tempMap = new HashMap<>();
        for (String str : list2) {
            tempMap.put(str, str);
        }
        //LinkedList 频繁添加删除 也可以ArrayList容量初始化为List1.size(),防止数据量过大时频繁扩容以及数组复制
        List<String> resList = new LinkedList<>();
        for (String str : list1) {
            if (!tempMap.containsKey(str)) {
                resList.add(str);
            }
        }
        return resList;
    }

    /**
     * 获取过去时间点
     *
     * @param type
     * @return
     */
    public static long getLastPeroid(int type, Date date) {
//        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String day = format.format(Date);
        Calendar c = Calendar.getInstance();
        if (0 == type) {
            //过去1天
            c.setTime(date);
            c.add(Calendar.DATE, -1);
            Date d = c.getTime();
            return d.getTime();
        } else if (1 == type) {
            //过去7天
            c.setTime(date);
            c.add(Calendar.DATE, -7);
            Date d = c.getTime();
            return d.getTime();
        } else if (2 == type) {
            //过去一月
            c.setTime(date);
            c.add(Calendar.MONTH, -1);
            Date m = c.getTime();
            return m.getTime();
        } else if (3 == type) {
            //过去一年
            c.setTime(date);
            c.add(Calendar.YEAR, -1);
            Date y = c.getTime();
            return y.getTime();
        } else if (4 == type) {
            //过去二十年
            c.setTime(date);
            c.add(Calendar.YEAR, -20);
            Date y = c.getTime();
            return y.getTime();
        }
        //过去1天
        c.setTime(date);
        c.add(Calendar.DATE, -1);
        Date d = c.getTime();

        return d.getTime();
    }


    /**
     * 获取当前月的上一个月
     *
     * @return
     */
    public static String getLastMonth(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date); // 设置为当前时间
        calendar.add(Calendar.MONTH, -1);
        date = calendar.getTime();
        String accDate = format.format(date);
        return accDate;
    }


    /**
     * 获取字段值
     *
     * @param urlStr 路径
     * @param field  字段名
     * @return
     */
    public static String getFieldValue(String urlStr, String field) {
        String result = "";
        Pattern pXM = Pattern.compile(field + "=([^&]*)");
        Matcher mXM = pXM.matcher(urlStr);
        while (mXM.find()) {
            result += mXM.group(1) + "";
        }
        return result;
    }

    /**
     * 根据当前时间获取几天后日期
     *
     * @param day  天数
     * @param date 当前时间
     * @return
     */
    public static String getDateTime(Date date, Integer day) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DATE, -7);
        Date d = c.getTime();
        return format.format(d);
    }

    /**
     * @param date   当前时间
     * @param minute 分钟
     * @return
     */
    public static String minuteDateTime(Date date, Integer minute) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(date);
        rightNow.add(Calendar.MINUTE, minute);
        Date dt2 = rightNow.getTime();
        String format = sdf.format(dt2);
        return format;
    }

    public static String timeChange(Object dateTime1) {
        SimpleDateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            //2020-09-19T09:58:34.926Z  转换为 2020-09-19 09:58:34  格式
            String dateTime = String.valueOf(dateTime1);
            Date date = utcFormat.parse(dateTime);
            return simpleDateFormat.format(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getDeviceTypeName(Integer deviceType) {
        String deviceName = "";
        switch (deviceType) {
            case 1:
                deviceName = "火系统";
                break;
            case 2:
                deviceName = "水系统";
                break;
            case 3:
                deviceName = "烟感系统";
                break;
            case 4:
                deviceName = "消防栓";
                break;
            case 5:
                deviceName = "液位";
                break;
            case 6:
                deviceName = "RTU";
                break;
            case 7:
                deviceName = "电气火灾";
                break;
            case 8:
                deviceName = "防火门";
                break;
            case 9:
                deviceName = "气体灭火";
                break;
            case 10:
                deviceName = "人脸识别";
                break;
            case 16:
                deviceName = "视频监控";
                break;
            case 128:
                deviceName = "井盖";
                break;
            default:
                deviceName = "" + deviceType;
                break;
        }
        return deviceName;
    }

    public static String alarmName(String alarmType) {
        String alarmName = alarmType;
        switch (alarmType) {
            case "2":
                alarmName = "火警";
                break;
            case "4":
                alarmName = "故障";
                break;
            case "16":
                alarmName = "监管";
                break;
            case "EF0":
                alarmName = "正常/报警撤销";
                break;
            case "EF1":
                alarmName = "欠压报警";
                break;
            case "EF2":
                alarmName = "过压报警";
                break;
            case "EF3":
                alarmName = "过流报警";
                break;
            case "EF4":
                alarmName = "漏电报警";
                break;
            case "EF5":
                alarmName = "温度1超高报警";
                break;
            case "EF6":
                alarmName = "温度2超高报警";
                break;
            case "EF7":
                alarmName = "温度3超高报警";
                break;
            case "EF8":
                alarmName = "温度4超高报警";
                break;
            case "EF9":
            case "WP4":
                alarmName = "离线";
                break;
            case "WP0":
            case "LL0":
                alarmName = "正常";
                break;
            case "WP1":
                alarmName = "低压";
                break;
            case "WP2":
                alarmName = "高压";
                break;
            case "WP3":
            case "LL3":
                alarmName = "故障";
                break;
            case "LL1":
                alarmName = "低水位";
                break;
            case "LL2":
                alarmName = "高湿度";
                break;
            case "y01":
                alarmName = "报警";
                break;
            case "y02":
                alarmName = "报警静音";
                break;
            case "y03":
            case "y06":
                alarmName = "保留";
                break;
            case "y04":
                alarmName = "低压";
                break;
            case "y05":
                alarmName = "故障";
                break;
            case "y07":
                alarmName = "火灾报警";
                break;
            case "y08":
                alarmName = "温度报警";
                break;
            case "y09":
                alarmName = "烟感电量低";
                break;
            case "y10":
                alarmName = "防拆报警";
                break;
            case "y11":
                alarmName = "发射电路故障";
                break;
            case "y12":
                alarmName = "设备自检";
                break;
        }
        return alarmName;
    }


    public static String company(String alarmType) {
        String company = "";
        switch (alarmType) {
            case "EF0":
            case "EF9":
                company = "";
                break;
            case "EF1":
            case "EF2":
                company = "V";
                break;
            case "EF3":
            case "EF4":
                company = "mA";
                break;
            case "EF5":
            case "EF6":
            case "EF7":
            case "EF8":
                company = "℃";
                break;
            case "WP0":
            case "WP1":
            case "WP2":
            case "WP3":
            case "WP4":
                company = "MPa";
                break;
            case "LL0":
            case "LL1":
            case "LL2":
            case "LL3":
                company = "m";
                break;
        }
        return company;
    }

    /**
     * 占比率计算
     *
     * @param y 总数
     * @param z 占比数
     * @return
     */
    public static String myPercent(int y, int z) {
        String baifenbi = "";// 接受百分比的值
        if (y == 0 && z == 0) {
            baifenbi = "0.00%";
        } else {
            double baiy = y * 1.0;
            double baiz = z * 1.0;
            double fen = baiy / baiz;
            DecimalFormat df1 = new DecimalFormat("##.00%");
            baifenbi = df1.format(fen);
            if (baifenbi.equals(".00%")) {
                baifenbi = "0.00%";
            }
        }
        return baifenbi;
    }

    /**
     * 起始条数计算
     *
     * @param pageNum  当前页
     * @param pageSize 每页条数
     * @return
     */
    public static Integer getStartFate(Integer pageNum, Integer pageSize) {
        return (pageNum - 1) * pageSize;
    }


    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param list     分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    public static List<PatrolInspectionAreaVo> getChildPerms(List<PatrolInspectionAreaVo> list, int parentId) {
        List<PatrolInspectionAreaVo> returnList = new ArrayList<PatrolInspectionAreaVo>();
        for (Iterator<PatrolInspectionAreaVo> iterator = list.iterator(); iterator.hasNext(); ) {
            PatrolInspectionAreaVo t = (PatrolInspectionAreaVo) iterator.next();
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (t.getAreaFid() == parentId) {
                recursionFn(list, t);
                returnList.add(t);
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     *
     * @param list
     * @param t
     */
    private static void recursionFn(List<PatrolInspectionAreaVo> list, PatrolInspectionAreaVo t) {
        // 得到子节点列表
        List<PatrolInspectionAreaVo> childList = getChildList(list, t);
        t.setChildren(childList);
        for (PatrolInspectionAreaVo tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }


    /**
     * 得到子节点列表
     */
    private static List<PatrolInspectionAreaVo> getChildList(List<PatrolInspectionAreaVo> list, PatrolInspectionAreaVo t) {
        List<PatrolInspectionAreaVo> tlist = new ArrayList<PatrolInspectionAreaVo>();
        Iterator<PatrolInspectionAreaVo> it = list.iterator();
        while (it.hasNext()) {
            PatrolInspectionAreaVo n = (PatrolInspectionAreaVo) it.next();
            if (n.getAreaFid().longValue() == t.getId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }


    /**
     * 判断是否有子节点
     */
    private static boolean hasChild(List<PatrolInspectionAreaVo> list, PatrolInspectionAreaVo t) {
        return getChildList(list, t).size() > 0 ? true : false;
    }

    /**
     * 计算两个日期相隔天数
     *
     * @param s1 日期1
     * @param s2 日期2
     * @return
     */
    public static int fun(LocalDate s1, LocalDate s2) {
        long between = ChronoUnit.DAYS.between(s1, s2);
        return (int) between;
    }

    /**
     * java获取指定日期的前几天或后几天
     *
     * @param dateStr 指定日期
     * @param format  日期格式
     * @param flag    true为获取后几天, false:为获取前几天
     * @param day     指定需要获取的天数
     * @returr
     */
    public static LocalDate getDate(String dateStr, String format, boolean flag, int day) {
        Calendar c = Calendar.getInstance();
        Date date = null;
        try {
            date = new SimpleDateFormat(format).parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        c.setTime(date);
        int day1 = c.get(Calendar.DATE);
        if (flag) {
            c.set(Calendar.DATE, day1 + day);
        } else {
            c.set(Calendar.DATE, day1 - day);
        }
        String m = new SimpleDateFormat(format).format(c.getTime());
        LocalDate beginDateTime = LocalDate.parse(m, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        return beginDateTime;
    }


    /**
     * 获取当前日期是星期几<br>
     *
     * @param date
     * @return 当前日期是星期几
     */

    public static String getWeekOfDate(Date date) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        return weekDays[w];
    }

    /**
     * 获取startDate日期后month月的日期
     *
     * @param startDate 开始日期
     * @param month     几个月后
     * @return
     */
    public static LocalDate getMonthDate(Date startDate, int month) {
        LocalDateTime localDateTime = startDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime().plusMonths(month);
        LocalDate localDate = localDateTime.toLocalDate();
//        Date date = Date.from(localDateTime.atZone( ZoneId.systemDefault()).toInstant());
        return localDate;
    }

    /**
     * String转Date
     *
     * @param timeStr 时间格式 yyyy-MM-dd
     * @return
     */
    public static Date getDate(String timeStr) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//设置日期格式
        Date date = null;
        try {
            date = df.parse(timeStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }


    /**
     * 保留2个小数
     *
     * @param value
     * @return
     */
    public static String format1(double value) {
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(2, RoundingMode.HALF_UP);
        return bd.toString();
    }
}
