package org.jeecg.modules.hikiot;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.hikiot.dto.AddDoorWeekPlanDTO;
import org.jeecg.modules.hikiot.dto.AddFaceRequestDTO;
import org.jeecg.modules.hikiot.dto.AddUserRequestDTO;
import org.jeecg.modules.hikiot.dto.AddUserWeekPlanDTO;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.alibaba.dashscope.utils.JsonUtils.gson;
import static org.jeecg.modules.hikiot.HikiotConstant.*;

public class HikiotTool {

    private static String cachedAppAccessToken = null;
    private static long expirationTime = 0L;
    private static String cachedUserAccessToken = null;
    private static long userTokenExpirationTime = 0L;
    private static final HttpClient httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .build();
    /**
     * 发送HTTPS POST请求
     * @param url 请求地址
     * @param jsonParam 请求参数（JSON格式）
     * @return 响应结果
     */
    public static String sendPostRequest(String url, String jsonParam, Map<String, String> variables) {
        // 参数校验
        Objects.requireNonNull(url, "请求URL不能为空");
        Objects.requireNonNull(jsonParam, "JSON参数不能为空");

        try {
            // 构建请求基础配置
            HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .header("Content-Type", "application/json; charset=UTF-8")
                    .POST(HttpRequest.BodyPublishers.ofString(jsonParam, StandardCharsets.UTF_8));

            // 添加自定义Header
            if (variables != null) {
                variables.forEach(requestBuilder::header);
            }

            // 构建最终请求
            HttpRequest request = requestBuilder.build();

            // 发送请求并返回结果
            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            return response.body();

        } catch (IOException e) {
            throw new JeecgBootException("请求海康开放平台接口IO异常", e);
        } catch (InterruptedException e) {
            // 恢复中断状态
            Thread.currentThread().interrupt();
            throw new JeecgBootException("请求海康开放平台接口被中断", e);
        }
    }
    /**
     * 发送HTTPS GET请求
     * @param url 完整请求地址（包含查询参数）
     * @return 响应结果
     */
    public static String sendGetRequest(String url, Map<String, String> headers){
        // 构建请求基础配置
        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .header("Content-Type", "application/json")
                .header(APP_ACCESS_TOKEN_AUTH_HEADER, getAppAccessToken());

        // 添加动态header
        if (headers != null) {
            headers.forEach(requestBuilder::header);
        }

        // 构建最终请求
        HttpRequest request = requestBuilder.build();
        HttpResponse<String> response = null;
        try {
            response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        }catch (Exception e){
            throw new JeecgBootException("请求海康开放平台接口异常", e);
        }
        return response.body();
    }

    /**
     * @Author SheepHy
     * @Description 获取应用访问凭证（带缓存）
     * @Date 16:05 2025/8/12
     **/
    public static synchronized String getAppAccessToken() {
        // 检查缓存是否有效
        if (cachedAppAccessToken != null && System.currentTimeMillis() < expirationTime) {
            return cachedAppAccessToken;
        }
        // 缓存失效或不存在，重新获取
        Map<String, String> map = new HashMap<>();
        map.put(APP_KEY, APP_KEY_VALUE);
        map.put(APP_SECRET, APP_SECRET_VALUE);
        JsonObject appAccessToken = JsonParser.parseString(HikiotTool.sendPostRequest(GET_ACCESS_TOKEN_URL, gson.toJson(map), null)).getAsJsonObject();
        if (appAccessToken.get("code").getAsInt() == 0) {
            JsonObject data = appAccessToken.getAsJsonObject("data");
            int expiresIn = data.get("expiresIn").getAsInt();
            String token = data.get("appAccessToken").getAsString();
            // 更新缓存和过期时间（单位：小时转毫秒）
            cachedAppAccessToken = token;
            expirationTime = System.currentTimeMillis() + (expiresIn * 60L * 60L * 1000L);
            return token;
        } else {
            throw new JeecgBootException("海康API appAccessToken请求失败: " + appAccessToken.get("msg").getAsString());
        }
    }

    /**
     * @Author SheepHy
     * @Description 刷新应用访问凭证
     * @Date 16:25 2025/8/12
     **/
    public static String refreshAppAccessToken(String appAccessToken, String refreshAppToken) {
        Map<String, String> map = new HashMap<>();
        map.put(APP_ACCESS_TOKEN, appAccessToken);
        map.put(REFRESH_APP_TOKEN, refreshAppToken);
        return HikiotTool.sendPostRequest(REFRESH_ACCESS_TOKEN_URL, gson.toJson(map), null);
    }

    /**
     * @Author SheepHy
     * @Description 申请授权码
     * @Date 14:04 2025/8/14
     * @Param
     * @return
     **/
    public static String getAuthCode() {
        Map<String, String> map = new HashMap<>();
        map.put(USER_NAME, USER_NAME_VALUE);
        map.put(PASSWORD, PASSWORD_VALUE);
        map.put(APP_KEY, APP_KEY_VALUE);
        map.put(REDIRECT_URL, REDIRECT_URL_VALUE);
        return HikiotTool.sendPostRequest(GET_AUTH_CODE_URL, gson.toJson(map), null);
    }

    /**
     * @Author SheepHy
     * @Description 授权码获取用户访问凭证（带缓存）
     * @Date 11:36 2025/8/14
     */
    public static synchronized String getUserAccessToken() {
        // 检查缓存是否有效
        if (cachedUserAccessToken != null && System.currentTimeMillis() < userTokenExpirationTime) {
            return cachedUserAccessToken;
        }
        // 缓存失效或不存在，重新获取
        JsonObject dataAuthCode = JsonParser.parseString(HikiotTool.getAuthCode()).getAsJsonObject();
        if (dataAuthCode.get("code").getAsInt() != 0) {
            throw new JeecgBootException("海康API authCode请求失败: " + dataAuthCode.get("msg").getAsString());
        }
        String authCode = dataAuthCode.getAsJsonObject("data").get("authCode").getAsString();
        JsonObject userAccessToken = JsonParser.parseString(sendGetRequest(GET_USER_ACCESS_TOKEN_URL + authCode, null)).getAsJsonObject();
        if (userAccessToken.get("code").getAsInt() != 0) {
            throw new JeecgBootException("海康API userAccessToken请求失败: " + userAccessToken.get("msg").getAsString());
        }
        JsonObject data = userAccessToken.getAsJsonObject("data");
        String expiresInStr = data.get("expiresIn").getAsString();
        try {
            int expiresInDays = Integer.parseInt(expiresInStr);
            String token = data.get("userAccessToken").getAsString();
            // 更新缓存和过期时间（单位：天转毫秒）
            cachedUserAccessToken = token;
            userTokenExpirationTime = System.currentTimeMillis() + (expiresInDays * 24L * 60L * 60L * 1000L);
            return token;
        } catch (NumberFormatException e) {
            throw new JeecgBootException("海康API expiresIn字段解析失败: " + expiresInStr, e);
        }
    }

    /** 
     * @Author SheepHy
     * @Description 新增/修改人员
     * @Date 9:35 2025/8/15
     **/
    public static String addUser(Date inputDate,String deviceSerial,String name,String employeeNo,Date endDate){
        LocalDateTime now = inputDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        LocalDateTime startOfDay = now.with(LocalTime.MIN); // 00:00
        LocalDateTime endOfDay = now.with(LocalTime.MAX);
        if(null != endDate){
            LocalDateTime outputDate = endDate.toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime()
                    .plusDays(1);
            endOfDay = outputDate.with(LocalTime.MAX);
        }
        AddUserRequestDTO addUserRequestDTO = new AddUserRequestDTO();
        List<AddUserRequestDTO.DoorRightPlan> doorRightPlans = new ArrayList<>();
        AddUserRequestDTO.DoorRightPlan doorRightPlan = new AddUserRequestDTO.DoorRightPlan();
        doorRightPlan.setDoorNo(1);
        doorRightPlan.setPlanTemplateId(Collections.singletonList(1));
        doorRightPlans.add(doorRightPlan);
        addUserRequestDTO.setDeviceSerial(deviceSerial);
        addUserRequestDTO.setPayload(new AddUserRequestDTO.Payload()
                .setUserInfo(new AddUserRequestDTO.UserInfo()
                        .setUserType("normal")
                        .setEmployeeNo(employeeNo)
                        .setName(name)
                        .setDoorRightPlan(doorRightPlans)
                        .setDoorRight(Collections.singletonList(1))
                        .setPermanentValid(false)
                        .setMaxOpenDoorTime(255)
                        .setEnableBeginTime(LocalDateTimeUtil.format(startOfDay, "yyyy-MM-dd'T'HH:mm:ss"))
                        .setEnableEndTime(LocalDateTimeUtil.format(endOfDay, "yyyy-MM-dd'T'HH:mm:ss"))));
        return sendPostRequest(ADD_USER_URL, gson.toJson(addUserRequestDTO),setHeaders());
    }

    /** 
     * @Author SheepHy
     * @Description 设备添加
     * @Date 10:47 2025/8/15
     **/
    public static String addDevice(String deviceSerial,String validateCode){
        Map<String, String> device = new HashMap<>();
        device.put("deviceSerial", deviceSerial);
        device.put("validateCode", validateCode);
        device.put("addMethod", "DeviceToken");
        device.put("qrCode", "");
        return sendPostRequest(ADD_DEVICE_URL, gson.toJson(device),setHeaders());
    }

    /**
     * @Author SheepHy
     * @Description 设置请求头
     * @Date 10:56 2025/8/15
     **/
    private static Map<String, String> setHeaders() {
        Map<String, String> variables = new HashMap<>();
        variables.put(APP_ACCESS_TOKEN_AUTH_HEADER, getAppAccessToken());
        variables.put(USER_ACCESS_TOKEN, getUserAccessToken());
        return variables;
    }

    /**
     * @Author SheepHy
     * @Description 设备/通道能力查询
     * @Date 12:00 2025/8/15
     **/
    public static String getDeviceAbility() throws IOException, InterruptedException {
        Map<String, String> headers = new HashMap<>();
        JsonObject userAccessToken = JsonParser.parseString(HikiotTool.getUserAccessToken()).getAsJsonObject();
        if (userAccessToken.get("code").getAsInt() == 0) {
            userAccessToken = userAccessToken.getAsJsonObject("data");
        }
        headers.put(USER_ACCESS_TOKEN, userAccessToken.get("userAccessToken").getAsString());
        return sendGetRequest(QUERY_DEVICE_ABILITY_URL + "FX0889961",headers);
    }

    /** 
     * @Author SheepHy
     * @Description 新增/修改人脸
     * @Date 14:28 2025/8/15
     **/
    public static String addFace(String deviceSerial,String employeeNo,String url){
        AddFaceRequestDTO addFaceRequestDTO = new AddFaceRequestDTO();
        addFaceRequestDTO.setDeviceSerial(deviceSerial);
        addFaceRequestDTO.setPayload(new AddFaceRequestDTO.Payload()
                .setFaceInfo(new AddFaceRequestDTO.Payload.FaceInfo()
                        .setEmployeeNo(employeeNo)
                        .setFaceURL(url)));
        return sendPostRequest(ADD_FACE_URL, gson.toJson(addFaceRequestDTO),setHeaders());
    }

    /**
     * @Author SheepHy
     * @Description 人员信息查询
     * @Date 15:08 2025/8/15
     **/
    public static String queryUserInfo(String deviceSerial){
        Map<String, String> queryUserInfo = new HashMap<>();
        queryUserInfo.put("deviceSerial", deviceSerial);
        return sendPostRequest(QUERY_USER_INFO_URL, gson.toJson(queryUserInfo),setHeaders());
    }

    /**
     * @Author SheepHy
     * @Description 删除已过期的访客
     * @Date 15:09 2025/8/15
     **/
    public static String deleteExpiredVisitors(String deviceSerial) {
        try {
            // 1. 查询访客信息
            String userInfoResponse = queryUserInfo(deviceSerial);
            JsonObject responseJson = JsonParser.parseString(userInfoResponse).getAsJsonObject();

            if (responseJson.get("code").getAsInt() != 0) {
                throw new JeecgBootException("查询用户信息失败: " + responseJson.get("msg").getAsString());
            }

            // 2. 解析并筛选过期访客
            List<String> expiredEmployees = new ArrayList<>();
            LocalDateTime now = LocalDateTime.now();
            JsonArray dataArray = responseJson.getAsJsonArray("data");

            for (JsonElement element : dataArray) {
                JsonObject user = element.getAsJsonObject();
                JsonObject valid = user.getAsJsonObject("Valid");

                // 解析时间字段
                String endTimeStr = valid.get("endTime").getAsString();
                LocalDateTime endTime = LocalDateTime.parse(endTimeStr, DateTimeFormatter.ISO_DATE_TIME);

                // 判断是否过期
                if (endTime.isBefore(now)) {
                    expiredEmployees.add(user.get("employeeNo").getAsString());
                }
            }

            // 3. 构造删除请求体
            if (expiredEmployees.isEmpty()) {
                return "无过期访客需要删除";
            }

            JsonObject requestJson = new JsonObject();
            requestJson.addProperty("deviceSerial", deviceSerial);  // deviceSerial在顶层

            // 创建payload对象
            JsonObject payload = new JsonObject();
            JsonArray userInfoArray = new JsonArray();

            // 添加userInfo数组
            for (String employeeNo : expiredEmployees) {
                JsonObject userInfoItem = new JsonObject();
                userInfoItem.addProperty("employeeNo", employeeNo);
                userInfoArray.add(userInfoItem);
            }

            payload.add("userInfo", userInfoArray);
            requestJson.add("payload", payload);  // payload作为顶层字段

            // 4. 发送删除请求
            return sendPostRequest(BATCH_DELETE_USER_URL, requestJson.toString(), setHeaders());

        } catch (Exception e) {
            throw new JeecgBootException("删除过期访客失败", e);
        }
    }

    /** 
     * @Author SheepHy
     * @Description 配置人员周计划
     * @Date 16:12 2025/8/15
     **/
    public static String addUserWeekPlan(String deviceSerial) {
        AddUserWeekPlanDTO dto = new AddUserWeekPlanDTO();

        // 基础配置
        dto.setDeviceSerial(deviceSerial);

        // 初始化payload
        AddUserWeekPlanDTO.Payload payload = new AddUserWeekPlanDTO.Payload();
        AddUserWeekPlanDTO.UserWeekPlan userWeekPlan = new AddUserWeekPlanDTO.UserWeekPlan();

        userWeekPlan.setDoorWeekId(1);
        userWeekPlan.setEnable(true);

        // 生成时间配置
        userWeekPlan.setTimeSegment(createTimeSegments());

        payload.setUserWeekPlan(userWeekPlan);
        dto.setPayload(payload);

        return sendPostRequest(CONFIG_USER_WEEK_PLAN_URL, gson.toJson(dto), setHeaders());
    }

    // 生成时间片段
    private static List<AddUserWeekPlanDTO.TimeSegment> createTimeSegments() {
        List<AddUserWeekPlanDTO.TimeSegment> segments = new ArrayList<>();
        // 默认时间片段配置
        for (String day : Arrays.asList("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")) {
            for (int i = 1; i <= 8; i++) {
                AddUserWeekPlanDTO.TimeSegment segment = new AddUserWeekPlanDTO.TimeSegment();
                segment.setDoorWeekTimeSegmentId(i);
                segment.setWeek(day);
                segment.setDoorStatus("normal");
                segment.setBeginTime("01:00:00");
                segment.setEndTime("23:00:00");

                // 特殊配置
                if (i == 1) {
                    segment.setEnable(true);
                    segment.setBeginTime("06:00:00");
                    segment.setEndTime("23:00:00");
                } else {
                    segment.setEnable(false);
                }
                segments.add(segment);
            }
        }
        return segments;
    }

    /**
     * @Author SheepHy
     * @Description 配置人员计划模板
     * @Date 17:09 2025/8/15
     **/
    public static String addUserPlanTemplate(String deviceSerial){
        String addUserPlanTemplate = "{\n" +
                "    \"deviceSerial\": \"" + deviceSerial +"\",\n" +
                "    \"payload\": {\n" +
                "        \"userPlanTemplate\": {\n" +
                "            \"doorPlanTemplateId\": 1,\n" +
                "            \"enable\": true,\n" +
                "            \"name\": \"全天通行计划模板\",\n" +
                "            \"doorWeekId\": 1,\n" +
                "            \"holidayGroupId\": [\n" +
                "                1\n" +
                "            ]\n" +
                "        }\n" +
                "    }\n" +
                "}";
        return sendPostRequest(CONFIG_USER_PLAN_TEMPLATE_URL, addUserPlanTemplate, setHeaders());
    }

    /**
     * @Author SheepHy
     * @Description 配置门周计划
     * @Date 16:42 2025/8/15
     **/
    public static String addDoorWeekPlan() throws IOException, InterruptedException {
        AddDoorWeekPlanDTO dto = new AddDoorWeekPlanDTO();
        // 基础配置
        dto.setDeviceSerial("FX0889961");
        // 初始化payload
        AddDoorWeekPlanDTO.Payload payload = new AddDoorWeekPlanDTO.Payload();
        AddDoorWeekPlanDTO.WeekPlan weekPlan = new AddDoorWeekPlanDTO.WeekPlan();
        weekPlan.setDoorWeekId(1);
        weekPlan.setEnable(true);
        // 生成时间配置
        weekPlan.setTimeSegment(createTimeSegments1());
        payload.setWeekPlan(weekPlan);
        dto.setPayload(payload);
        return sendPostRequest(CONFIG_DOOR_WEEK_PLAN_URL, gson.toJson(dto), setHeaders());
    }
    private static List<AddDoorWeekPlanDTO.TimeSegment> createTimeSegments1() {
        List<AddDoorWeekPlanDTO.TimeSegment> segments = new ArrayList<>();

        List<String> days = Arrays.asList(
                "Monday", "Tuesday", "Wednesday", "Thursday",
                "Friday", "Saturday", "Sunday"
        );

        for (String day : days) {
            for (int i = 1; i <= 8; i++) {
                AddDoorWeekPlanDTO.TimeSegment segment = new AddDoorWeekPlanDTO.TimeSegment();
                segment.setDoorWeekTimeSegmentId(i);
                segment.setWeek(day);

                // 设置默认值
                segment.setBeginTime("01:00:00");
                segment.setEndTime("23:00:00");

                // 特殊配置
                if (i == 1 ) {
                    segment.setEnable(true);
                    segment.setBeginTime("06:00:00");
                    segment.setEndTime("23:00:00");
                } else {
                    segment.setEnable(false);
                }

                segments.add(segment);
            }
        }

        return segments;
    }

    /**
     * @Author SheepHy
     * @Description 配置门关联计划模板
     * @Date 16:48 2025/8/15
     **/
    public static String addDoorPlanTemplate() throws IOException, InterruptedException {
        String str = "{\n" +
                "    \"deviceSerial\": \"FX0889961\",\n" +
                "    \"payload\": {\n" +
                "        \"doorRightPlan\": {\n" +
                "            \"doorNo\": 1,\n" +
                "            \"planTemplateId\": 1\n" +
                "        }\n" +
                "    }\n" +
                "}";
        return sendPostRequest(CONFIG_DOOR_PLAN_TEMPLATE_URL, str, setHeaders());
    }

    /**
     * @Author SheepHy
     * @Description 配置门计划模板
     * @Date 16:51 2025/8/15
     **/
    public static String addDoorPlanTemplate1() throws IOException, InterruptedException {
        String str = "{\n" +
                "    \"deviceSerial\": \"FX0889961\",\n" +
                "    \"payload\": {\n" +
                "        \"planTemplate\": {\n" +
                "            \"doorPlanTemplateId\": 1,\n" +
                "            \"enable\": true,\n" +
                "            \"name\": \"全天常开计划模板\",\n" +
                "            \"doorWeekId\": 1,\n" +
                "            \"holidayGroupId\": [\n" +
                "                1\n" +
                "            ]\n" +
                "        }\n" +
                "    }\n" +
                "}";
        return sendPostRequest(CONFIG_DOOR_PLAN_TEMPLATE_URL2, str, setHeaders());
    }

    /**
     * @Author SheepHy
     * @Description 分页查询开门记录
     * @Date 10:05 2025/8/25
     **/
    public static JsonObject queryOpenDoorRecord(int page, int size, Date startOfDay) {
        Map<String, Object> queryOpenDoor = new HashMap<>();
        queryOpenDoor.put("page", page);
        queryOpenDoor.put("size", size);
        // 获取今天最早和最晚时间并格式化
        LocalDate today = LocalDate.now();
        if(null != startOfDay){
            queryOpenDoor.put("startDate", DateUtil.format(startOfDay, "yyyy-MM-dd HH:mm:ss"));
        }
//        queryOpenDoor.put("endDate", endOfDay.format(formatter));
        queryOpenDoor.put("authResults", new int[] {1});
//        queryOpenDoor.put("employeeNos", new String[] {employeeNos});
//        queryOpenDoor.put("deviceSerial", "FX0889961");
//        queryOpenDoor.put("deviceSerials", new String[] {"FX0889961"});
        return gson.fromJson(sendPostRequest(QUERY_OPEN_DOOR_RECORD_URL, gson.toJson(queryOpenDoor), setHeaders()), JsonObject.class);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
//        addUserPlanTemplate("FX0889961");
//        deleteExpiredVisitors("FX0889961");
//        queryUserInfo("FX0889961");
        addUserWeekPlan("FX0889961");
        addUser(new Date(),"FX0889961","Sheep","1999",null);
        addFace("FX0889961","1999","https://national-motion.oss-cn-beijing.aliyuncs.com/opt/upFiles/tmp_81fc8aa195d37dac70fd57221d82845e_1756361097600.jpg");
//        addUser(new Date(),"FX0889961","Sheep123","10011");
//        addFace("FX0889961","1001","https://national-motion.oss-cn-beijing.aliyuncs.com/opt/upFiles/tmp_81fc8aa195d37dac70fd57221d82845e_1756361097600.jpg");
//        addUser();
//        addUserPlanTemplate();
//        addFace();
//        addUserWeekPlan();
//        JsonObject root = JsonParser.parseString(HikiotTool.getAppAccessToken()).getAsJsonObject();
//        JsonObject data;
//        if (root.get("code").getAsInt() == 0) {
//            data = root.getAsJsonObject("data");
//            sendGetRequest(GET_USER_ACCESS_TOKEN_URL + AUTH_CODE + "FX0889961", data.get("appAccessToken").getAsString());
//        } else {
//            throw new JeecgBootException("海康API 请求失败: " + root.get("msg").getAsString());
//        }
    }
}
