package com.lanyuanxiaoyao.service.sync.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.lanyuanxiaoyao.service.common.Constants;
import com.lanyuanxiaoyao.service.common.entity.FlinkJob;
import com.lanyuanxiaoyao.service.common.entity.TableMeta;
import com.lanyuanxiaoyao.service.sync.configuration.GlobalConfiguration;
import com.lanyuanxiaoyao.service.sync.configuration.RetryPolicyProvider;
import dev.failsafe.Failsafe;
import java.util.Map;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hudi.common.model.HoodieCommitMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 状态输出
 *
 * @author ZhangJiacheng
 * @date 2022-07-05
 */
public class StatusUtils {
    private static final Logger logger = LoggerFactory.getLogger(StatusUtils.class);

    private static final ObjectMapper MAPPER = JacksonUtils.getMapper();
    private static final int HTTP_TIMEOUT = (int) Constants.MINUTE;

    public static void syncStart(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() ->
                            HttpUtil.createGet(
                                            StrUtil.format(
                                                    "{}/api/sync_start?flink_job_id={}&alias={}&database={}&schema={}&table={}&cluster={}&application_id={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    tableMeta.getSource(),
                                                    tableMeta.getSchema(),
                                                    tableMeta.getTable(),
                                                    configuration.getCluster(),
                                                    configuration.getApplicationId()
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("sync start metrics submit failure");
        }
    }

    public static void syncCheckpoint(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, String messageId) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() -> HttpUtil.createGet(
                                            StrUtil.format(
                                                    "{}/api/sync_checkpoint?flink_job_id={}&alias={}&message_id={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    messageId
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("sync checkpoint metrics submit failure");
        }
    }

    public static void syncLatestPublishTime(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, Long publishTime) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() -> HttpUtil.createGet(
                                            StrUtil.format(
                                                    "{}/api/sync_latest_publish_time?flink_job_id={}&alias={}&publish_time={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    publishTime
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("sync latest publish time submit failure");
        }
    }

    public static void syncLatestReceiveTime(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, Long receiveTime) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() ->
                            HttpUtil.createGet(
                                            StrUtil.format(
                                                    "{}/api/sync_latest_receive_time?flink_job_id={}&alias={}&receive_time={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    receiveTime
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("sync latest receive time submit failure");
        }
    }

    public static void syncLatestOperationTime(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, Long operationTime) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() ->
                            HttpUtil.createGet(
                                            StrUtil.format(
                                                    "{}/api/sync_latest_operation_time?flink_job_id={}&alias={}&operation_time={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    operationTime
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("sync latest operation metrics submit failure");
        }
    }

    public static void compactionStart(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() ->
                            HttpUtil.createGet(
                                            StrUtil.format(
                                                    "{}/api/compaction_start?flink_job_id={}&alias={}&cluster={}&application_id={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    configuration.getCluster(),
                                                    configuration.getApplicationId()
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("compaction start metrics submit failure");
        }
    }

    public static void compactionPreCommit(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, String instant, Map<String, Long> metadata) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() -> HttpUtil.createPost(
                                            StrUtil.format(
                                                    "{}/api/compaction_pre_commit?flink_job_id={}&alias={}&instant={}&cluster={}&application_id={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    instant,
                                                    configuration.getCluster(),
                                                    configuration.getApplicationId()
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .body(MAPPER.writeValueAsString(metadata))
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("compaction pre commit metrics submit failure");
        }
    }

    public static void compactionCommit(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, String instant, HoodieCommitMetadata metadata) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() -> HttpUtil.createPost(
                                            StrUtil.format(
                                                    "{}/api/compaction_commit?flink_job_id={}&alias={}&instant={}&cluster={}&application_id={}",
                                                    LoadBalance.getCustomPublishUrl(configuration),
                                                    flinkJob.getId(),
                                                    tableMeta.getAlias(),
                                                    instant,
                                                    configuration.getCluster(),
                                                    configuration.getApplicationId()
                                            )
                                    )
                                    .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                    .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                    .body(MAPPER.writeValueAsString(metadata))
                                    .timeout(HTTP_TIMEOUT)
                                    .execute()
                    );
        } catch (Exception e) {
            logger.warn("compaction commit metrics submit failure");
        }
    }

    public static void compactionFinish(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, String message, Exception exception) {
        try {
            Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                    .run(() -> {
                        boolean success = (exception == null);
                        HttpUtil.createPost(StrUtil.format(
                                        "{}/api/compaction_finish?flink_job_id={}&alias={}&state={}",
                                        LoadBalance.getCustomPublishUrl(configuration),
                                        flinkJob.getId(),
                                        tableMeta.getAlias(),
                                        success
                                ))
                                .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                .body(success ? message == null ? "success" : message : exception.toString(), "text/plain")
                                .timeout(HTTP_TIMEOUT)
                                .execute()
                                .close();
                    });
        } catch (Exception e) {
            logger.warn("compaction finish metrics submit failure");
        }
    }

    public static void versionUpdate(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, String version, String operationTime) {
        logger.info("Enter method: versionUpdate[configuration, flinkJob, tableMeta, version, opts]. " + "configuration:" + configuration + "," + "flinkJob:" + flinkJob.getId() + "," + "tableMeta:" + tableMeta.getAlias() + "," + "version:" + version + "," + "opts:" + operationTime);
        Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                .run(() ->
                        HttpUtil.createGet(
                                        StrUtil.format(
                                                "{}/api/version_update?flink_job_id={}&alias={}&version={}&operation_time={}",
                                                LoadBalance.getCustomPublishUrl(configuration),
                                                flinkJob.getId(),
                                                tableMeta.getAlias(),
                                                version,
                                                operationTime
                                        )
                                )
                                .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                .timeout(HTTP_TIMEOUT)
                                .execute()
                );
    }

    public static void compactionLatestOperationTime(GlobalConfiguration configuration, FlinkJob flinkJob, TableMeta tableMeta, Long operationTime) {
        Failsafe.with(RetryPolicyProvider.HTTP_RETRY)
                .run(() ->
                        HttpUtil.createGet(
                                        StrUtil.format(
                                                "{}/api/compaction_latest_operation_time?flink_job_id={}&alias={}&operation_time={}",
                                                LoadBalance.getCustomPublishUrl(configuration),
                                                flinkJob.getId(),
                                                tableMeta.getAlias(),
                                                operationTime
                                        )
                                )
                                .header(Constants.API_HEADER_NAME, Constants.API_VERSION)
                                .basicAuth(Constants.SPRING_SECURITY_USERNAME, Constants.SPRING_SECURITY_PASSWORD_PLAIN)
                                .timeout(HTTP_TIMEOUT)
                                .execute()
                );
    }
}
