package com.lanyuanxiaoyao.service.api.controller;

import cn.hutool.core.util.StrUtil;
import com.github.loki4j.slf4j.marker.LabelMarker;
import com.lanyuanxiaoyao.service.api.entity.HoodieCommitMetadata;
import com.lanyuanxiaoyao.service.api.service.SyncStateService;
import com.lanyuanxiaoyao.service.api.service.VersionUpdateService;
import com.lanyuanxiaoyao.service.common.Constants;
import javax.annotation.Resource;
import org.eclipse.collections.api.factory.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.springframework.web.bind.annotation.*;

/**
 * Rest 接口
 *
 * @author ZhangJiacheng
 * @date 2022-07-05
 */
@RequestMapping("api")
@RestController
public class ApiController {
    private static final Logger logger = LoggerFactory.getLogger(ApiController.class);

    @Resource
    private SyncStateService syncStateService;
    @Resource
    private VersionUpdateService versionUpdateService;

    private Marker makeMarker(Long flinkJobId, String alias) {
        return LabelMarker.of(() -> Maps.mutable.of(Constants.LOG_FLINK_JOB_ID, flinkJobId.toString(), Constants.LOG_ALIAS, alias));
    }

    @ResponseBody
    @GetMapping("message_id")
    public String messageId(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Get message id: {} {}", flinkJobId, alias);
        return syncStateService.getMessageId(flinkJobId, alias);
    }

    @GetMapping("sync_start")
    public void syncStart(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam(value = "cluster", required = false) String cluster,
            @RequestParam(value = "application_id", required = false) String applicationId
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Sync start: {} {} {} {}", flinkJobId, alias, cluster, applicationId);
        syncStateService.saveSyncStartTime(flinkJobId, alias, cluster, applicationId);
    }

    @GetMapping("sync_checkpoint_state")
    public void syncCheckpointState(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam("message_id") String messageId,
            @RequestParam("publish_time") Long publishTime
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Sync checkpoint state: {} {} {} {}", flinkJobId, alias, messageId, publishTime);
        syncStateService.saveSyncCheckpointState(flinkJobId, alias, messageId, publishTime);
    }

    @GetMapping("sync_operation_state")
    public void syncOperationState(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam(value = "operation_time",
                    required = false) Long operationTime
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Sync operation state: {} {} {}", flinkJobId, alias, operationTime);
        syncStateService.saveSyncOperationState(flinkJobId, alias, operationTime);
    }

    @GetMapping("compaction_start")
    public void compactionStart(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam(value = "type", required = false) String type,
            @RequestParam(value = "cluster", required = false) String cluster,
            @RequestParam(value = "application_id", required = false) String applicationId
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Compaction start: {} {} {} {}", flinkJobId, alias, cluster, applicationId);
        syncStateService.saveCompactionStartTime(flinkJobId, alias, cluster, applicationId, null);
    }

    @PostMapping("compaction_pre_commit")
    public void compactionPreCommit(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam("instant") String instant,
            @RequestParam(value = "cluster", required = false) String cluster,
            @RequestParam(value = "application_id", required = false) String applicationId,
            @RequestBody HoodieCommitMetadata metadata
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Compaction state: {} {} {} {} {}", flinkJobId, alias, instant, cluster, applicationId);
        syncStateService.saveCompactionMetrics(
                flinkJobId,
                alias,
                "pre",
                instant,
                cluster,
                applicationId
        );
    }

    @PostMapping("compaction_commit")
    public void compactionCommit(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam("instant") String instant,
            @RequestParam(value = "cluster", required = false) String cluster,
            @RequestParam(value = "application_id", required = false) String applicationId,
            @RequestBody HoodieCommitMetadata metadata
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Compaction state: {} {} {} {} {}", flinkJobId, alias, instant, cluster, applicationId);
        syncStateService.saveCompactionFinishTime(flinkJobId, alias);
        syncStateService.saveCompactionMetrics(
                flinkJobId,
                alias,
                "complete",
                instant,
                cluster,
                applicationId
        );
    }

    @PostMapping("compaction_finish")
    public void compactionFinish(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam("time") Long timestamp,
            @RequestParam("state") Boolean success,
            @RequestBody(required = false) String exception
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Compaction finish: {} {} {} {}", flinkJobId, alias, timestamp, success);
        syncStateService.saveCompactionFinishTime(flinkJobId, alias, timestamp, StrUtil.isBlank(exception) ? null : exception);
    }

    @GetMapping("version_update")
    public void versionUpdate(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam("version") String version,
            @RequestParam(value = "opts", defaultValue = "") String opTs
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Version update: {} {} {}", flinkJobId, alias, version);
        versionUpdateService.saveUpdateVersion(flinkJobId, alias, version, opTs);
    }

    @GetMapping("compaction_latest_operation_time")
    public void compactionLatestOperationTime(
            @RequestParam("flink_job_id") Long flinkJobId,
            @RequestParam("alias") String alias,
            @RequestParam("latest_op_ts") Long latestOpTs
    ) {
        logger.info(makeMarker(flinkJobId, alias), "Compaction latest operation time: {} {} {}", flinkJobId, alias, latestOpTs);
        syncStateService.saveCompactionLatestOperationTime(flinkJobId, alias, latestOpTs);
    }
}
