package com.lanyuanxiaoyao.service.info.service;

import club.kingon.sql.builder.SqlBuilder;
import club.kingon.sql.builder.entry.Column;
import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.service.common.entity.FlinkJob;
import com.lanyuanxiaoyao.service.common.entity.TableMeta;
import com.lanyuanxiaoyao.service.common.exception.FlinkJobNotFoundException;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

import static com.lanyuanxiaoyao.service.common.SQLConstants.HudiCollectBuild.TbAppFlinkJobConfig;
import static com.lanyuanxiaoyao.service.common.SQLConstants.HudiCollectBuild.TbAppYarnJobConfig;

/**
 * Flink Job
 *
 * @author lanyuanxiaoyao
 * @date 2024-01-03
 */
@CacheConfig(cacheManager = "normal-cache")
@Service
public class FlinkJobService extends BaseService {
    private static final Logger logger = LoggerFactory.getLogger(FlinkJobService.class);
    private final JdbcTemplate mysqlJdbcTemplate;

    public FlinkJobService(JdbcTemplate mysqlJdbcTemplate) {
        this.mysqlJdbcTemplate = mysqlJdbcTemplate;
    }

    private ImmutableList<FlinkJob> flinkJobList(Long flinkJobId) {
        return Lists.immutable.ofAll(
                mysqlJdbcTemplate.query(
                        SqlBuilder.select(
                                        TbAppFlinkJobConfig.ID_A,
                                        TbAppFlinkJobConfig.NAME_A,
                                        TbAppFlinkJobConfig.RUN_MODE_A,
                                        TbAppYarnJobConfig.JOB_MANAGER_MEMORY_A,
                                        TbAppYarnJobConfig.TASK_MANAGER_MEMORY_A
                                )
                                .from(TbAppFlinkJobConfig._alias_)
                                .leftJoin(TbAppYarnJobConfig._alias_)
                                .onEq(TbAppFlinkJobConfig.ONE_IN_ONE_YARN_JOB_ID_A, Column.as(TbAppYarnJobConfig.ID_A))
                                .whereEq(TbAppFlinkJobConfig.STATUS_A, STATUS_Y)
                                .andEq(ObjectUtil.isNotNull(flinkJobId), TbAppFlinkJobConfig.ID_A, flinkJobId)
                                .build(),
                        (rs, row) -> {
                            String runModeText = rs.getString(3);
                            FlinkJob.RunMode mode;
                            try {
                                mode = FlinkJob.RunMode.valueOf(runModeText);
                            } catch (IllegalArgumentException e) {
                                mode = FlinkJob.RunMode.ALL_IN_ONE;
                            }
                            TableMeta.YarnMeta yarnMeta = TableMeta.YarnMeta.builder()
                                    .jobManagerMemory(rs.getInt(4))
                                    .taskManagerMemory(rs.getInt(5))
                                    .build();
                            return FlinkJob.builder()
                                    .id(rs.getLong(1))
                                    .name(rs.getString(2))
                                    .runMode(mode)
                                    .oneInOneSyncYarn(yarnMeta)
                                    .build();
                        })
        );
    }

    @Cacheable(value = "flink-jobs", sync = true)
    @Retryable(Throwable.class)
    public ImmutableList<FlinkJob> flinkJobs() {
        return flinkJobList(null);
    }

    @Cacheable(value = "flink-jobs", sync = true, key = "#flinkJobId")
    @Retryable(Throwable.class)
    public FlinkJob flinkJob(Long flinkJobId) {
        return flinkJobList(flinkJobId)
                .getFirstOptional()
                .orElseThrow(() -> new FlinkJobNotFoundException(flinkJobId));
    }

    @Retryable(Throwable.class)
    public void saveFlinkJob(Long id, String name, String runMode) {
        mysqlJdbcTemplate.update(
                SqlBuilder
                        .insertInto(
                                TbAppFlinkJobConfig._origin_,
                                TbAppFlinkJobConfig.ID_O,
                                TbAppFlinkJobConfig.NAME_O,
                                TbAppFlinkJobConfig.RUN_MODE_O,
                                TbAppFlinkJobConfig.STATUS_O,
                                TbAppFlinkJobConfig.COMMENT_O
                        )
                        .values()
                        .addValue(Q, Q, Q, Q, Q)
                        .precompileSql(),
                id, name, runMode, STATUS_Y, 3);
    }
}
