package com.usky.cdi.service.util;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;

/**
 * 天气数据获取工具类
 * 使用OpenWeatherMap API获取天气数据，并进行缓存
 * @author fyc
 * @email yuchuan.fu@chinausky.com
 * @date 2025/12/15
 */
@Slf4j
public class WeatherFetcher {
    private static final String API_KEY = "d04f0f84421a99b9b66dd99243c36db4";
    private static final String CITY_NAME = "shanghai,cn";
    private static final String API_URL = "https://api.openweathermap.org/data/2.5/weather?q=" + CITY_NAME + "&appid=" + API_KEY;

    // 缓存相关字段
    private static final Map<String, Double> weatherCache = new ConcurrentHashMap<>();
    private static long lastUpdateTime = 0;
    private static final long CACHE_EXPIRE_TIME = 30 * 60 * 1000;  // 缓存30分钟

    // 默认天气数据，当API调用失败时使用
    private static final double DEFAULT_TEMPERATURE = 15.0;
    private static final int DEFAULT_HUMIDITY = 40;

    // 异步执行的线程池
    private static final ExecutorService WEATHER_FETCHER_POOL = Executors.newFixedThreadPool(3);
    private static final int ASYNC_TIMEOUT = 5000; // 异步调用超时时间：5秒

    /**
     * 获取天气数据
     * 1. 优先使用缓存数据（如果缓存有效）
     * 2. 缓存无效时，异步调用API获取新数据
     * 3. API调用失败或超时，使用默认值
     *
     * @return 包含温度和湿度的Map
     */
    public static Map<String, Double> fetchWeather() {
        // 1. 检查缓存是否有效
        long currentTime = System.currentTimeMillis();
        synchronized (WeatherFetcher.class) {
            if (!weatherCache.isEmpty() && (currentTime - lastUpdateTime) < CACHE_EXPIRE_TIME) {
                log.debug("使用缓存的天气数据，温度：{}°C，湿度：{}%",
                        weatherCache.get("temperature"), weatherCache.get("humidity"));
                return new HashMap<>(weatherCache);
            }
        }

        // 2. 如果缓存无效，返回当前缓存值（如果有）或默认值
        Map<String, Double> fallbackData = new HashMap<>();
        synchronized (WeatherFetcher.class) {
            if (!weatherCache.isEmpty()) {
                fallbackData.putAll(weatherCache);
                log.debug("缓存已过期，使用过期缓存作为临时数据");
            } else {
                fallbackData.put("temperature", DEFAULT_TEMPERATURE);
                fallbackData.put("humidity", (double) DEFAULT_HUMIDITY);
                log.debug("缓存为空，使用默认天气数据作为临时数据");
            }
        }

        // 3. 异步调用API更新缓存，不阻塞主线程
        CompletableFuture.supplyAsync(() -> {
            long asyncStartTime = System.currentTimeMillis();
            double tempCelsius = DEFAULT_TEMPERATURE;
            int humidity = DEFAULT_HUMIDITY;

            try {
                log.info("开始异步调用OpenWeatherMap API获取天气数据");
                // 1. 构造请求URL
                URL url = new URL(API_URL);

                // 2. 建立连接并发送请求
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(10000); // 减少超时时间到10秒
                conn.setReadTimeout(10000);

                // 3. 读取响应
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                reader.close();

                // 4. 解析JSON数据（使用org.json库）
                JSONObject jsonResponse = new JSONObject(response.toString());
                JSONObject main = jsonResponse.getJSONObject("main");

                // 注意：温度默认是开尔文单位，转换为摄氏度需要 -273.15
                double tempKelvin = main.getDouble("temp");
                tempCelsius = tempKelvin - 273.15;
                humidity = main.getInt("humidity");
                double feelsLikeKelvin = main.getDouble("feels_like");
                double feelsLikeCelsius = feelsLikeKelvin - 273.15;

                // 提取天气状况描述
                JSONObject weather = jsonResponse.getJSONArray("weather").getJSONObject(0);
                String description = weather.getString("description");

                // 记录日志
                log.info("=== 天气解析结果 ===");
                log.info("城市: {}", jsonResponse.getString("name"));
                log.info("温度: {:.2f}°C (原始: {}K)", tempCelsius, tempKelvin);
                log.info("体感温度: {:.2f}°C", feelsLikeCelsius);
                log.info("湿度: {}%", humidity);
                log.info("天气状况: {}", description);
                log.info("时区偏移: {}小时", (jsonResponse.getInt("timezone") / 3600));

                // 检查是否包含臭氧数据
                if (jsonResponse.has("air_quality") || jsonResponse.has("o3") || jsonResponse.has("components")) {
                    log.info("包含空气质量数据");
                } else {
                    log.info("当前数据不包含臭氧浓度等空气质量指标");
                }

                // 更新缓存
                synchronized (WeatherFetcher.class) {
                    weatherCache.clear();
                    weatherCache.put("temperature", tempCelsius);
                    weatherCache.put("humidity", (double) humidity);
                    lastUpdateTime = System.currentTimeMillis();
                    log.info("天气数据缓存更新成功");
                }

            } catch (Exception e) {
                log.error("异步获取天气数据失败：{}", e.getMessage());
                // 异常时使用默认值，但不更新缓存
            } finally {
                // 打印API调用结束时间和时长
                long asyncEndTime = System.currentTimeMillis();
                long duration = asyncEndTime - asyncStartTime;
                log.info("OpenWeatherMap API异步调用结束，时长: {}ms", duration);
            }

            return null;
        }, WEATHER_FETCHER_POOL);

        // 立即返回临时数据，不等待异步调用完成
        return fallbackData;
    }

    /**
     * 关闭线程池（仅用于测试或应用关闭时）
     */
    public static void shutdown() {
        WEATHER_FETCHER_POOL.shutdown();
        try {
            if (!WEATHER_FETCHER_POOL.awaitTermination(5, TimeUnit.SECONDS)) {
                WEATHER_FETCHER_POOL.shutdownNow();
            }
        } catch (InterruptedException e) {
            WEATHER_FETCHER_POOL.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    public static void main(String[] args) {
        fetchWeather();
    }
}