package cn.reghao.tnb.sb.aliyun;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import cn.reghao.jutil.jdk.converter.DateTimeConverter;
import cn.reghao.jutil.jdk.security.RsaCryptor;
import cn.reghao.jutil.jdk.serializer.JsonConverter;
import cn.reghao.jutil.jdk.shell.ShellExecutor;
import cn.reghao.jutil.jdk.shell.ShellResult;
import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
import com.aliyun.auth.credentials.Credential;
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
import com.aliyun.sdk.service.cas20200407.AsyncClient;
import com.aliyun.sdk.service.cas20200407.models.*;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import darabonba.core.client.ClientOverrideConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author reghao
 * @date 2025-03-27 16:14:53
 */
@Slf4j
public class AliyunCertificate {
    static ScheduledExecutorService scheduler = ThreadPoolWrapper.scheduledThreadPool("checker", 10);
    static Map<Long, ScheduledFuture<?>> futureMap = new HashMap<>();

    static void setLogLevel() {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        Logger rootLogger = loggerContext.getLogger("ROOT");
        rootLogger.setLevel(Level.INFO);
    }

    public static void main(String[] args) throws Exception {
        setLogLevel();

        StaticCredentialProvider provider = StaticCredentialProvider.create(Credential.builder()
                .accessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
                .accessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
                //.securityToken(System.getenv("ALIBABA_CLOUD_SECURITY_TOKEN")) // use STS token
                .build());

        // Endpoint 请参考 https://api.aliyun.com/product/cas
        String endpoint = "cas.aliyuncs.com";
        AsyncClient client = AsyncClient.builder()
                .credentialsProvider(provider)
                .overrideConfiguration(
                        ClientOverrideConfiguration.create()
                                .setEndpointOverride(endpoint)
                )
                .build();

        String orderType = "";
        //orderType = "CERT";
        listUserCertificateOrder(client, orderType);
        log.info("main-thread goto sleep...");
        Thread.sleep(3600_000);

        //createCertificate(client);
        long orderId = 13588158L;
        //describeCertificateState(client, orderId);
        // Finally, close the client
        client.close();
    }

    static void listUserCertificateOrder(AsyncClient client, String orderType) throws Exception {
        ListUserCertificateOrderRequest listUserCertificateOrderRequest;
        if (orderType.isBlank()) {
            listUserCertificateOrderRequest = ListUserCertificateOrderRequest.builder()
                    .build();
        } else {
            listUserCertificateOrderRequest = ListUserCertificateOrderRequest.builder()
                    .orderType(orderType)
                    .build();
        }

        CompletableFuture<ListUserCertificateOrderResponse> response = client.listUserCertificateOrder(listUserCertificateOrderRequest);
        ListUserCertificateOrderResponse resp = response.get();
        String jsonData = new Gson().toJson(resp);
        JsonObject jsonObject = JsonConverter.jsonToObject(jsonData, JsonObject.class);
        JsonArray jsonArray = jsonObject.get("body").getAsJsonObject().get("certificateOrderList").getAsJsonArray();
        for (JsonElement jsonElement : jsonArray) {
            JsonObject jsonObject1 = jsonElement.getAsJsonObject();
            if (orderType.isBlank()) {
                long orderId = jsonObject1.get("orderId").getAsLong();
                describeCertificateState(client, orderId);

                /*String domain = jsonObject1.get("domain").getAsString();
                long endTimeMs = jsonObject1.get("certEndTime").getAsLong();
                LocalDateTime expireDateTime = DateTimeConverter.localDateTime(endTimeMs);*/
            } else {
                long certificateId = jsonObject1.get("certificateId").getAsLong();
                getUserCertificateDetail(client, certificateId);
            }
        }
    }

    static void getUserCertificateDetail(AsyncClient client, long certificateId) throws Exception {
        GetUserCertificateDetailRequest getUserCertificateDetailRequest = GetUserCertificateDetailRequest.builder()
                .certId(certificateId)
                .certFilter(false)
                .build();

        CompletableFuture<GetUserCertificateDetailResponse> response = client.getUserCertificateDetail(getUserCertificateDetailRequest);
        GetUserCertificateDetailResponse resp = response.get();
        String jsonData = new Gson().toJson(resp);
        JsonObject jsonObject = JsonConverter.jsonToObject(jsonData, JsonObject.class);
        JsonObject certDetail = jsonObject.get("body").getAsJsonObject();
        String domain = certDetail.get("sans").getAsString();
        String certificate = certDetail.get("cert").getAsString();
        String privateKey = certDetail.get("key").getAsString();
        long notBefore = certDetail.get("notBefore").getAsLong();
        long notAfter = certDetail.get("notAfter").getAsLong();
        LocalDateTime expireDateTime = DateTimeConverter.localDateTime(notAfter);

        String certPath = String.format("/home/reghao/Downloads/1/%s.pem", domain);
        File certFile = new File(certPath);
        if (!certFile.exists()) {
            RsaCryptor.savePemFile(certificate, certPath);
        }

        String keyPath = String.format("/home/reghao/Downloads/1/%s.key", domain);;
        File keyFile = new File(keyPath);
        if (!keyFile.exists()) {
            RsaCryptor.savePemFile(privateKey, keyPath);
        }
        System.out.println();
    }

    static void createCertificates(AsyncClient client) throws Exception {
        List<String> domainList = List.of("tnb.reghao.cn", "api.reghao.cn", "oss.reghao.cn", "bnt.reghao.cn");
        List<String> domainList1 = List.of("blog.reghao.cn", "git.reghao.cn", "docker.reghao.cn");
        for (String domain : domainList) {
            createCertificate(client, domain);
            Thread.sleep(5_000);
        }
    }

    static void createCertificate(AsyncClient client, String domain) throws ExecutionException, InterruptedException {
        CreateCertificateRequestRequest createCertificateRequestRequest = CreateCertificateRequestRequest.builder()
                .productCode("digicert-free-1-free")
                .username("赵梓潼")
                .phone("18782243510")
                .email("lhao.sg@qq.com")
                .domain(domain)
                .validateType("DNS")
                .build();

        CompletableFuture<CreateCertificateRequestResponse> response = client.createCertificateRequest(createCertificateRequestRequest);
        CreateCertificateRequestResponse resp = response.get();
        String jsonData = new Gson().toJson(resp);
        JsonObject jsonObject = JsonConverter.jsonToObject(jsonData, JsonObject.class);
        JsonObject respBody = jsonObject.get("body").getAsJsonObject();
        long orderId = respBody.get("orderId").getAsLong();
        log.info("orderId -> {}", orderId);
    }

    static void describeCertificateState(AsyncClient client, long orderId) throws ExecutionException, InterruptedException {
        DescribeCertificateStateRequest describeCertificateStateRequest = DescribeCertificateStateRequest.builder()
                .orderId(orderId)
                .build();

        CompletableFuture<DescribeCertificateStateResponse> response = client.describeCertificateState(describeCertificateStateRequest);
        DescribeCertificateStateResponse resp = response.get();
        String jsonData = new Gson().toJson(resp);
        JsonObject jsonObject = JsonConverter.jsonToObject(jsonData, JsonObject.class);
        JsonObject respBody = jsonObject.get("body").getAsJsonObject();
        String type = respBody.get("type").getAsString();
        if ("certificate".equals(type)) {
            String certificate = respBody.get("certificate").getAsString();
            String privateKey = respBody.get("privateKey").getAsString();
        } else if ("domain_verify".equals(type)) {
            String recordDomain = respBody.get("recordDomain").getAsString();
            String recordType = respBody.get("recordType").getAsString();
            String recordValue = respBody.get("recordValue").getAsString();
            String domain = recordDomain.replace("_dnsauth.", "");
            // 添加 TXT 记录
            AliyunDns.addTxtRecord(domain, recordDomain, recordValue);

            CheckTask checkTask = new CheckTask(client, domain, orderId);
            ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(checkTask, 60, 60, TimeUnit.SECONDS);
            futureMap.put(orderId, future);
            Thread.sleep(5_000);
        }
    }

    static class CheckTask implements Runnable {
        private final AsyncClient client;
        private final String domain;
        private final long orderId;

        public CheckTask(AsyncClient client, String domain, long orderId) {
            this.client = client;
            this.domain = domain;
            this.orderId = orderId;
        }

        public void run() {
            try {
                DescribeCertificateStateRequest describeCertificateStateRequest = DescribeCertificateStateRequest.builder()
                        .orderId(orderId)
                        .build();

                CompletableFuture<DescribeCertificateStateResponse> response = client.describeCertificateState(describeCertificateStateRequest);
                DescribeCertificateStateResponse resp = response.get();
                String jsonData = new Gson().toJson(resp);
                JsonObject jsonObject = JsonConverter.jsonToObject(jsonData, JsonObject.class);
                JsonObject respBody = jsonObject.get("body").getAsJsonObject();
                String type = respBody.get("type").getAsString();
                if ("certificate".equals(type)) {
                    String certificate = respBody.get("certificate").getAsString();
                    String privateKey = respBody.get("privateKey").getAsString();
                    ScheduledFuture<?> future = futureMap.get(orderId);
                    if (future != null) {
                        log.info("{} - {} 证书已签发, 取消定时任务...", domain, orderId);
                        future.cancel(true);
                    }
                } else {
                    log.info("{} - {} 证书状态 {}...", domain, orderId, type);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    static void reloadNginx() {
        ShellExecutor shellExecutor = new ShellExecutor();
        String cmd = "/usr/bin/nginx -t";
        String cmd1 = "/usr/bin/nginx -s reload";
        ShellResult shellResult = shellExecutor.exec(cmd.split("\\s+"));
        String result = shellResult.getResult();
        System.out.println(result);
    }
}
