package com.lanyuanxiaoyao.service.web.controller;

import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.service.configuration.ExecutorProvider;
import com.lanyuanxiaoyao.service.configuration.entity.flink.FlinkCheckpoint;
import com.lanyuanxiaoyao.service.configuration.entity.flink.FlinkOverview;
import com.lanyuanxiaoyao.service.forest.service.FlinkService;
import com.lanyuanxiaoyao.service.web.controller.base.AmisCrudResponse;
import com.lanyuanxiaoyao.service.web.controller.base.AmisResponse;
import com.lanyuanxiaoyao.service.web.controller.base.BaseController;
import com.lanyuanxiaoyao.service.web.entity.FlinkVertexVO;
import java.util.concurrent.ExecutionException;
import org.eclipse.collections.api.list.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Flink 接口
 *
 * @author lanyuanxiaoyao
 * @date 2023-05-05
 */
@RestController
@RequestMapping("flink")
public class FlinkController extends BaseController {
    private static final Logger logger = LoggerFactory.getLogger(FlinkController.class);

    private final FlinkService flinkService;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    public FlinkController(FlinkService flinkService) {
        this.flinkService = flinkService;
    }

    @GetMapping("overview")
    public AmisResponse<FlinkOverview> overview(@RequestParam("url") String url) throws ExecutionException, InterruptedException {
        return AmisResponse.responseSuccess(flinkService.overview(url));
    }

    @GetMapping("jobs")
    public AmisCrudResponse jobs(
            @RequestParam("url") String url,
            @RequestParam(value = "mode", required = false) String mode,
            @RequestParam(value = "schema", required = false) String schema,
            @RequestParam(value = "table", required = false) String table
    ) {
        boolean isAllInOne = StrUtil.isNotBlank(mode) && StrUtil.equals(mode, "ALL_IN_ONE");
        boolean isFilterSchema = StrUtil.isNotBlank(schema);
        boolean isFilterTable = StrUtil.isNotBlank(table);
        ImmutableList<FlinkVertexVO> vertexVOS = flinkService.vertexOverview(url)
                .getJobs()
                .asParallel(ExecutorProvider.EXECUTORS, 1)
                .collect(vertex -> flinkService.vertex(url, vertex.getJid()))
                .select(vertex -> !isFilterSchema || StrUtil.contains(vertex.getName(), schema))
                .select(vertex -> isAllInOne || (!isFilterTable || StrUtil.contains(vertex.getName(), table)))
                .collect(vertex -> {
                    ImmutableList<FlinkVertexVO.FlinkVertexChildVO> children = vertex.getChildren()
                            // 过滤名字中包含相关内容的算子
                            .select(child ->
                                    StrUtil.contains(child.getName(), "compaction_source")
                                            || StrUtil.contains(child.getName(), "compact_task")
                                            || StrUtil.contains(child.getName(), "compaction_commit")
                                            || (!isFilterTable || StrUtil.contains(child.getName(), table))
                            )
                            .collect(child -> new FlinkVertexVO.FlinkVertexChildVO(child, StrUtil.format("{}/#/job/{}/overview/{}", url, vertex.getJid(), child.getJid())));
                    ImmutableList<FlinkCheckpoint> checkpoints = flinkService.checkpointOverview(url, vertex.getJid())
                            .getHistory()
                            .asParallel(ExecutorProvider.EXECUTORS, 1)
                            .collect(checkpoint -> flinkService.checkpoint(url, vertex.getJid(), checkpoint.getId()))
                            .toSortedListBy(FlinkCheckpoint::getId)
                            .reverseThis()
                            .toImmutable();
                    return new FlinkVertexVO(vertex, StrUtil.format("{}/#/job/{}", url, vertex.getJid()), children, checkpoints);
                })
                .toSortedListBy(FlinkVertexVO::getName)
                .toImmutable();
        return AmisResponse.responseCrudData(vertexVOS, vertexVOS.size());
    }
}
