package org.dromara.manager.weathermanager;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Base64;

/**
 * @author lcj
 * @date 2025/5/12 17:33
 */
@Slf4j
@Component
public class WeatherManager {

    @Resource
    private WeatherProperties weatherProperties;

    /**
     * 获取天气
     *
     * @param lng         经度
     * @param lat         纬度
     * @param weatherPath 天气请求路径
     * @return 天气信息字符串
     */
    public String getWeather(String lng, String lat, String weatherPath) {
        // 获取小数点后两位的经纬度
        String lngTwo = roundToTwoDecimalPlacesString(lng);
        String latTwo = roundToTwoDecimalPlacesString(lat);
        String location = lngTwo + "," + latTwo;
        // 获取天气请求路径
        String dayWeatherUrl = getDayWeatherUrl(weatherPath, location);
        String body;
        try (HttpResponse result = HttpRequest.get(dayWeatherUrl)
            .header("Authorization", "Bearer " + getJwt())
            .execute()) {
            int status = result.getStatus();
            if (status != HttpStatus.SUCCESS) {
                log.error("获取天气失败，状态码：{}，body：{}", status, result.body());
                throw new ServiceException("获取天气失败，状态码：" + status, HttpStatus.ERROR);
            }
            body = result.body();
        }
        return body;
    }

    /**
     * 获取天气预报 Url
     *
     * @param weatherPath 天气请求路径
     * @param location    位置
     */
    private String getDayWeatherUrl(String weatherPath, String location) {
        return String.format("https://%s%s?location=%s", weatherProperties.getApiHost(), weatherPath, location);
    }

    /**
     * 获取小数点后两位的经纬度
     *
     * @param value 经纬度
     */
    private String roundToTwoDecimalPlacesString(String value) {
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(2, RoundingMode.HALF_UP); // 使用 RoundingMode.HALF_UP
        return bd.toPlainString(); // 防止科学计数法
    }


    /**
     * 获取 JWT
     */
    private String getJwt() {
        // Private key
        String privateKeyString = weatherProperties.getPrivateKey()
            .replace("-----BEGIN PRIVATE KEY-----", "")
            .replace("-----END PRIVATE KEY-----", "")
            .trim();
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        PrivateKey privateKey;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("EdDSA");
            privateKey = keyFactory.generatePrivate(keySpec);
        } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
            throw new ServiceException("获取天气失败，加密错误", HttpStatus.ERROR);
        }
        // Header
        String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"" + weatherProperties.getKeyId() + "\"}";
        // Payload
        long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30;
        long exp = iat + 900;
        String payloadJson = "{\"sub\": \"" + weatherProperties.getProjectId() + "\", \"iat\": " + iat + ", \"exp\": " + exp + "}";
        // Base64url header + payload
        String headerEncoded = Base64.getUrlEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
        String payloadEncoded = Base64.getUrlEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
        String data = headerEncoded + "." + payloadEncoded;
        // Sign
        byte[] signature;
        try {
            Signature signer = Signature.getInstance("EdDSA");
            signer.initSign(privateKey);
            signer.update(data.getBytes(StandardCharsets.UTF_8));
            signature = signer.sign();
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new ServiceException("获取天气失败，加密错误", HttpStatus.ERROR);
        }
        String signatureString = Base64.getUrlEncoder().encodeToString(signature);
        return data + "." + signatureString;
    }

}
