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 cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.service.common.entity.SyncState;
import com.lanyuanxiaoyao.service.common.exception.SyncStateNotFoundException;
import java.sql.Timestamp;
import java.util.function.Function;
import org.eclipse.collections.api.factory.Lists;
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.*;

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

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

    @Cacheable(value = "sync-state", sync = true, key = "#flinkJobId.toString()+#alias")
    @Retryable(Throwable.class)
    public SyncState syncState(Long flinkJobId, String alias) {
        return Lists.immutable.ofAll(
                mysqlJdbcTemplate.query(
                        SqlBuilder.select(
                                        TbAppFlinkJobConfig.ID_A,
                                        TbAppCollectTableInfo.ALIAS_A,
                                        TbAppHudiSyncState.MESSAGE_ID_A,
                                        TbAppHudiSyncState.SOURCE_START_TIME_A,
                                        TbAppHudiSyncState.SOURCE_CHECKPOINT_TIME_A,
                                        TbAppHudiSyncState.SOURCE_PUBLISH_TIME_A,
                                        TbAppHudiSyncState.SOURCE_OP_TIME_A,
                                        TbAppHudiSyncState.COMPACTION_START_TIME_A,
                                        TbAppHudiSyncState.COMPACTION_FINISH_TIME_A,
                                        TbAppHudiSyncState.COMPACTION_APPLICATION_ID_A,
                                        TbAppHudiSyncState.COMPACTION_STATUS_A,
                                        TbAppHudiSyncState.COMPACTION_STATUS_TIME_A,
                                        TbAppHudiSyncState.COMPACTION_LATEST_OP_TS_A
                                )
                                .from(
                                        TbAppFlinkJobConfig._alias_,
                                        TbAppCollectTableInfo._alias_,
                                        TbAppHudiSyncState._alias_
                                )
                                .whereEq(TbAppFlinkJobConfig.ID_A, Column.as(TbAppCollectTableInfo.FLINK_JOB_ID_A))
                                .andEq(TbAppHudiSyncState.ID_A, Column.as(StrUtil.format("concat({}, '-', {})", TbAppFlinkJobConfig.ID_A, TbAppCollectTableInfo.ALIAS_A)))
                                .andEq(TbAppFlinkJobConfig.STATUS_A, STATUS_Y)
                                .andEq(TbAppCollectTableInfo.STATUS_A, STATUS_Y)
                                .andEq(ObjectUtil.isNotNull(flinkJobId), TbAppFlinkJobConfig.ID_A, flinkJobId)
                                .andEq(StrUtil.isNotBlank(alias), TbAppCollectTableInfo.ALIAS_A, alias)
                                .build(),
                        (rs, row) -> {
                            Function<Timestamp, Long> dateConvertor = timestamp -> timestamp == null ? 0 : timestamp.getTime();
                            return SyncState.builder()
                                    .flinkJobId(rs.getLong(1))
                                    .alias(rs.getString(2))
                                    .messageId(rs.getString(3))
                                    .sourceStartTime(dateConvertor.apply(rs.getTimestamp(4)))
                                    .sourceCheckpointTime(dateConvertor.apply(rs.getTimestamp(5)))
                                    .sourcePublishTime(dateConvertor.apply(rs.getTimestamp(6)))
                                    .sourceOperationTime(dateConvertor.apply(rs.getTimestamp(7)))
                                    .compactionStartTime(dateConvertor.apply(rs.getTimestamp(8)))
                                    .compactionFinishTime(dateConvertor.apply(rs.getTimestamp(9)))
                                    .compactionApplicationId(rs.getString(10))
                                    .compactionStatus(rs.getString(11))
                                    .compactionStatusTime(dateConvertor.apply(rs.getTimestamp(12)))
                                    .compactionLatestOperationTime(dateConvertor.apply(rs.getTimestamp(13)))
                                    .build();
                        }
                )
        ).getFirstOptional().orElseThrow(SyncStateNotFoundException::new);
    }

    public void saveCompactionApplicationId(Long flinkJobId, String alias, String applicationId) {
        mysqlJdbcTemplate.update(
                SqlBuilder
                        .insertInto(TbAppHudiSyncState._origin_, TbAppHudiSyncState.ID_O, TbAppHudiSyncState.COMPACTION_APPLICATION_ID_O)
                        .values()
                        .addValue(Q, Q)
                        .onDuplicateKeyUpdateColumn(TbAppHudiSyncState.COMPACTION_APPLICATION_ID_O)
                        .precompileSql(),
                StrUtil.format("{}-{}", flinkJobId, alias),
                applicationId
        );
    }
}
