package com.lanyuanxiaoyao.service.web.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.eshore.odcp.hudi.connector.entity.FlinkJob;
import com.eshore.odcp.hudi.connector.entity.SyncState;
import com.eshore.odcp.hudi.connector.entity.TableMeta;
import com.lanyuanxiaoyao.service.configuration.entity.AmisResponse;
import com.lanyuanxiaoyao.service.configuration.entity.PageResponse;
import com.lanyuanxiaoyao.service.configuration.entity.info.JobIdAndAlias;
import com.lanyuanxiaoyao.service.forest.service.CompactionYarnService;
import com.lanyuanxiaoyao.service.forest.service.InfoService;
import com.lanyuanxiaoyao.service.forest.service.SyncYarnService;
import com.lanyuanxiaoyao.service.web.entity.SyncStateVO;
import com.lanyuanxiaoyao.service.web.entity.TableVO;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.map.MutableMap;
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;

/**
 * 表
 *
 * @author lanyuanxiaoyao
 * @date 2023-04-24
 */
@RestController
@RequestMapping("table")
public class TableController extends BaseController {
    private static final Logger logger = LoggerFactory.getLogger(TableController.class);
    private static final ExecutorService EXECUTOR = Executors.newWorkStealingPool(20);
    private final InfoService infoService;
    private final SyncYarnService syncYarnService;
    private final CompactionYarnService compactionYarnService;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    public TableController(InfoService infoService, SyncYarnService syncYarnService, CompactionYarnService compactionYarnService) {
        this.infoService = infoService;
        this.syncYarnService = syncYarnService;
        this.compactionYarnService = compactionYarnService;
    }

    @GetMapping("list")
    public AmisResponse list(
            @RequestParam(value = "page", defaultValue = "1") Integer page,
            @RequestParam(value = "count", defaultValue = "10") Integer count,
            @RequestParam(value = "order", required = false) String order,
            @RequestParam(value = "direction", required = false) String direction,
            @RequestParam(value = "search_flink_job_id", required = false) String searchFlinkJobId,
            @RequestParam(value = "search_alias", required = false) String searchAlias,
            @RequestParam(value = "filter_run_mode", required = false) List<String> runMode,
            @RequestParam(value = "filter_compaction_status", required = false) List<String> compactionStatus
    ) {

        /*CompletableFuture<ImmutableList<YarnApplication>> syncAppsFuture = CompletableFuture.supplyAsync(syncYarnService::jobList, EXECUTOR);
        CompletableFuture<ImmutableList<YarnApplication>> compactionAppsFuture = CompletableFuture.supplyAsync(compactionYarnService::jobList, EXECUTOR);
        AsyncUtil.waitAll(syncAppsFuture, compactionAppsFuture);
        ImmutableList<YarnApplication> syncApps = AsyncUtil.get(syncAppsFuture);
        ImmutableList<YarnApplication> compactionApps = AsyncUtil.get(compactionAppsFuture);*/
        MutableMap<String, Object> queryMap = Maps.mutable.empty();
        queryMap.put("page", page);
        queryMap.put("count", count);
        if (StrUtil.isNotBlank(searchFlinkJobId)) {
            queryMap.put("flink_job_id", searchFlinkJobId);
        }
        if (StrUtil.isNotBlank(searchAlias)) {
            queryMap.put("alias", searchAlias);
        }
        if (StrUtil.isNotBlank(order) && StrUtil.isNotBlank(direction)) {
            queryMap.put("order", order);
            queryMap.put("direction", direction);
        }
        if (ObjectUtil.isNotEmpty(runMode)) {
            queryMap.put("filter_run_mode", runMode);
        }
        if (ObjectUtil.isNotEmpty(compactionStatus)) {
            queryMap.put("filter_compaction_status", compactionStatus);
        }
        PageResponse<JobIdAndAlias> pageResponse = infoService.jobIdAndAlias(queryMap);
        Long total = pageResponse.getTotal();
        ImmutableList<TableVO> tableVOS = Lists.immutable.ofAll(pageResponse.getData())
                .asParallel(EXECUTOR, 1)
                .collect(item -> {
                    CompletableFuture<FlinkJob> flinkJobFuture = CompletableFuture.supplyAsync(() -> infoService.flinkJobDetail(item.getId()), EXECUTOR);
                    CompletableFuture<TableMeta> tableMetaFuture = CompletableFuture.supplyAsync(() -> infoService.tableMetaDetail(item.getId(), item.getAlias()), EXECUTOR);
                    CompletableFuture<SyncState> syncStateFuture = CompletableFuture.supplyAsync(() -> infoService.syncStateDetail(item.getId(), item.getAlias()), EXECUTOR);
                    try {
                        CompletableFuture.allOf(flinkJobFuture, tableMetaFuture, syncStateFuture).get();
                        return new TableVO(flinkJobFuture.get(), tableMetaFuture.get(), new SyncStateVO(syncStateFuture.get()));
                    } catch (InterruptedException | ExecutionException e) {
                        return null;
                    }
                })
                .reject(ObjectUtil::isNull)
                .toList()
                .toImmutable();
        return responseCrudData(tableVOS, tableVOS.size() == 0 ? 0 : total);
    }

    @GetMapping("list_metas")
    public AmisResponse listTableMetas(@RequestParam("flink_job_id") Long flinkJobId) throws Exception {
        if (ObjectUtil.isNull(flinkJobId)) {
            throw new Exception("flink job id is null");
        }
        return responseCrudData(infoService.tableMetaList(flinkJobId).collect(meta -> new TableVO(null, meta, null)));
    }
}
