package com.ruoyi.system.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.system.domain.EpsInitialTrafficData;
import com.ruoyi.system.domain.RmRegistrationMachine;
import com.ruoyi.system.service.EpsInitialTrafficDataService;
import com.ruoyi.system.service.IRmRegistrationMachineService;
import com.ruoyi.system.util.TableRouterUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.net.URI;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Component
public class HmacScheduledTask {

    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";

    @Autowired
    private IRmRegistrationMachineService rmRegistrationMachineService;
    @Autowired
    private EpsInitialTrafficDataService epsInitialTrafficDataService;


    /**
     * 每小时执行一次，查询4小时前的数据
     * 例如：9:39执行时查询4:00-5:00的数据
     */
    @Scheduled(cron = "0 0 * * * ?")  // 每小时整点执行
    // 或者每5分钟执行一次：@Scheduled(cron = "0 */5 * * * ?")
//    @Scheduled(initialDelay = 5000, fixedDelay = Long.MAX_VALUE)
    public void executeHourlyTask() {
        RestTemplate restTemplate = new RestTemplate();
        try {
            System.out.println("开始执行定时任务，时间：" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

            // 计算时间范围：当前时间往前推4小时的整点时间段
            LocalDateTime now = LocalDateTime.now();

            // 计算查询的时间段（4小时前的整点小时）
            LocalDateTime queryBaseTime = now.minusHours(4);
            LocalDateTime startTime = queryBaseTime.withMinute(0).withSecond(0).withNano(0);
            LocalDateTime endTime = startTime.plusHours(1);

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String startTimeStr = startTime.format(formatter);
            String endTimeStr = endTime.format(formatter);

            System.out.println("查询时间范围：" + startTimeStr + " 至 " + endTimeStr);

            long timestamp = System.currentTimeMillis();
            String plainText = "efea5f0218c84a24b9fdab3264de3da5" + timestamp + "/supplier/outer/dev/getFlow";
            String secretKey = getHmac(plainText, "91a73fd806ab2c005c13b4dc19130a884e909dea3f72d46e30266fe1a1f588d8");

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.set("Content-Type", "application/json");
            headers.set("TOKEN", "efea5f0218c84a24b9fdab3264de3da5");
            headers.set("secret-key", secretKey);
            headers.set("timestamps", String.valueOf(timestamp));
            // 查询绑定的machinecode
            List<RmRegistrationMachine> machineList = rmRegistrationMachineService.selectRmRegistrationMachineList(new RmRegistrationMachine());
            for (RmRegistrationMachine rmRegistrationMachine : machineList) {
                // 构建URL
                URI uri = UriComponentsBuilder
                        .fromHttpUrl("https://ecscm-openapi.ksyun.com/supplier/outer/dev/getFlow")
                        .queryParam("srmChannel", "1000121954")
                        .queryParam("startTime", startTimeStr)
                        .queryParam("endTime", endTimeStr)
                        .queryParam("machineCode", rmRegistrationMachine.getMachineCode())
                        .build()
                        .toUri();

                HttpEntity<String> entity = new HttpEntity<>(headers);

                // GET 请求
                ResponseEntity<String> response = restTemplate.exchange(
                        uri,
                        HttpMethod.GET,
                        entity,
                        String.class
                );
                String result = response.getBody();
                // 保存流量数据
                parseAndProcessResponse(result, rmRegistrationMachine.getClientId());
            }
            System.out.println("定时任务执行完成");

        } catch (Exception e) {
            System.err.println("定时任务执行失败：" + e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * 解析和处理API响应
     */
    private void parseAndProcessResponse(String responseBody, String clientId) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);

            if (responseMap.get("code").equals(200)) {
                Map<String, Object> dataMap = (Map<String, Object>) responseMap.get("data");
                Integer total = (Integer) dataMap.get("total");
                List<Map<String, Object>> dataList = (List<Map<String, Object>>) dataMap.get("data");

                System.out.println("成功获取数据，总记录数：" + total);

                // 处理每条数据
                for (Map<String, Object> item : dataList) {
                    processFlowData(item, clientId);
                }

            } else {
                System.out.println("API返回错误：" + responseMap.get("msg"));
            }
        } catch (Exception e) {
            System.err.println("JSON解析失败：" + e.getMessage());
        }
    }

    /**
     * 处理单条流量数据
     */
    private void processFlowData(Map<String, Object> flowData, String clientId) {
        String time = (String) flowData.get("time");
        // 科学计数法转换为BigDecimal
        BigDecimal flow = Optional.ofNullable(flowData.get("flow"))
                .map(Object::toString)
                .map(str -> {
                    try {
                        return new BigDecimal(str);
                    } catch (NumberFormatException e) {
                        return BigDecimal.ZERO;
                    }
                })
                .orElse(BigDecimal.ZERO);
        // 字节转bit
        flow = flow.multiply(new BigDecimal(8));
        String flowPlain = flow.toPlainString();
        String deviceid = (String) flowData.get("deviceid");
        String ip = (String) flowData.get("ip");
        String province = (String) flowData.get("province");

        System.out.println(String.format("时间：%s, 流量：%.2f, 设备：%s, IP：%s, 省份：%s",
                time, flow, deviceid, ip, province));

        String tableName = TableRouterUtil.getTableName(TableRouterUtil.parseDateTime(time));
        EpsInitialTrafficData epsInitialTrafficData = new EpsInitialTrafficData();
        epsInitialTrafficData.setTableName(tableName);
        epsInitialTrafficData.setCreateTime(DateUtils.parseDate(time));
        epsInitialTrafficData.setClientId(clientId);
        epsInitialTrafficData.setMachineFlow(flowPlain);
        epsInitialTrafficDataService.updateMachineTraffic(epsInitialTrafficData);
    }

    /**
     * 测试方法：手动执行查询指定时间段
     */
    public void manualExecuteForTimeRange(LocalDateTime start, LocalDateTime end) {
        RestTemplate restTemplate = new RestTemplate();
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String startTimeStr = start.format(formatter);
            String endTimeStr = end.format(formatter);

            System.out.println("手动执行查询，时间范围：" + startTimeStr + " 至 " + endTimeStr);

            long timestamp = System.currentTimeMillis();
            String plainText = "efea5f0218c84a24b9fdab3264de3da5" + timestamp + "/supplier/outer/dev/getFlow";
            String secretKey = getHmac(plainText, "91a73fd806ab2c005c13b4dc19130a884e909dea3f72d46e30266fe1a1f588d8");

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.set("Content-Type", "application/json");
            headers.set("TOKEN", "efea5f0218c84a24b9fdab3264de3da5");
            headers.set("secret-key", secretKey);
            headers.set("timestamps", String.valueOf(timestamp));

            // 构建URL
            URI uri = UriComponentsBuilder
                    .fromHttpUrl("https://ecscm-openapi.ksyun.com/supplier/outer/dev/getFlow")
                    .queryParam("srmChannel", "1000121954")
                    .queryParam("startTime", startTimeStr)
                    .queryParam("endTime", endTimeStr)
                    .build()
                    .toUri();

            HttpEntity<String> entity = new HttpEntity<>(headers);

            // GET 请求
            ResponseEntity<String> response = restTemplate.exchange(
                    uri,
                    HttpMethod.GET,
                    entity,
                    String.class
            );

            System.out.println("手动执行API响应结果：" + response.getBody());

        } catch (Exception e) {
            System.err.println("手动执行失败：" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * HMAC加密方法
     */
    public static String getHmac(String plainText, String encryptKey) {
        try{
            byte[] dataKey = encryptKey.getBytes(ENCODING);
            byte[] dataValue = plainText.getBytes(ENCODING);
            SecretKey secretKey = new SecretKeySpec(dataKey, MAC_NAME);
            Mac mac = Mac.getInstance(MAC_NAME);
            mac.init(secretKey);
            byte[] bytes = mac.doFinal(dataValue);
            String rs = encodeHex(bytes, false);
            return rs;
        } catch (Exception e){
            throw new IllegalArgumentException(e.getMessage());
        }
    }

    /**
     * 数据转16进制编码
     */
    public static String encodeHex(final byte[] data, final boolean toLowerCase) {
        final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        final char[] toDigits = toLowerCase ? DIGITS_LOWER : DIGITS_UPPER;
        final int l = data.length;
        final char[] out = new char[l << 1];
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = toDigits[0x0F & data[i]];
        }
        return new String(out);
    }
}