package ru.yandex.webmaster3.storage.clickhouse.dao;

import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import org.joda.time.DateTime;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.storage.clickhouse.ClickhouseTableInfo;
import ru.yandex.webmaster3.storage.clickhouse.TableSource;
import ru.yandex.webmaster3.storage.clickhouse.TableState;
import ru.yandex.webmaster3.storage.clickhouse.TableType;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.DataMapper;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Field;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Fields;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.RowMapper;

/**
 * @author aherman
 */
@Repository
public class LegacyClickhouseTablesYDao extends AbstractYDao implements ClickhouseTablesRepository {

    public LegacyClickhouseTablesYDao() {
        super(PREFIX_IMPORTER, "legacy_clickhouse_tables");
    }

    public List<ClickhouseTableInfo> listTables() {
        return select(MAPPER).queryForList().stream()
                .filter(c -> c.getType() != null)
                .collect(Collectors.toList());
    }

    public List<ClickhouseTableInfo> listTables(TableType tableType) {
        return select(MAPPER).where(F.TABLE_TYPE.eq(tableType)).queryForList().stream()
                .filter(c -> c.getType() != null)
                .collect(Collectors.toList());
    }

    /**
     * Добавляет или обновляет запись об указанной таблице
     */
    public void update(ClickhouseTableInfo tableInfo) {
        upsert(
                F.TABLE_TYPE.value(tableInfo.getType()),
                F.TABLE_ID.value(tableInfo.getTableId()),
                F.TABLE_STATE.value(tableInfo.getState()),
                F.STATE_DATE.value(tableInfo.getUpdateDate()),
                F.SOURCE.value(tableInfo.getSource()),
                F.SOURCE_TABLE.value(tableInfo.getSourcePath()),
                F.FULL_TABLE_NAME.value(tableInfo.getClickhouseFullName()),
                F.DISTRIBUTED_TABLE_NAME.value(tableInfo.getDistributedTableName()),
                F.LOCAL_TABLE_NAME.value(tableInfo.getLocalTableName()),
                F.SHARD_COUNT.value(tableInfo.getShardCount()),
                F.PART_COUNT.value(tableInfo.getPartCount())
        ).execute();
    }

    public void delete(ClickhouseTableInfo tableInfo) {
        delete().where(F.TABLE_ID.eq(tableInfo.getTableId()))
                .and(F.TABLE_TYPE.eq(tableInfo.getType()))
                .execute();
    }

    private static final RowMapper<ClickhouseTableInfo> MAPPER =
            DataMapper.create(F.TABLE_TYPE, F.TABLE_ID, F.TABLE_STATE, F.STATE_DATE, F.SOURCE, F.SOURCE_TABLE,
                    F.FULL_TABLE_NAME, F.DISTRIBUTED_TABLE_NAME, F.LOCAL_TABLE_NAME, F.SHARD_COUNT, F.PART_COUNT,
                    ClickhouseTableInfo::new);


    private interface F {
        Field<TableType> TABLE_TYPE = Fields.stringEnumField("table_type", TableType.R);
        Field<UUID> TABLE_ID = Fields.uuidField("table_id");
        Field<TableState> TABLE_STATE = Fields.stringEnumField("table_state", TableState.R).makeOptional();
        Field<DateTime> STATE_DATE = Fields.jodaDateTimeField("state_date").makeOptional();
        Field<TableSource> SOURCE = Fields.stringEnumField("source", TableSource.R).makeOptional();
        Field<String> SOURCE_TABLE = Fields.stringField("source_table").makeOptional();
        Field<String> FULL_TABLE_NAME = Fields.stringField("full_table_name").makeOptional();
        Field<String> DISTRIBUTED_TABLE_NAME = Fields.stringField("distributed_table_name").makeOptional();
        Field<String> LOCAL_TABLE_NAME = Fields.stringField("local_table_name").makeOptional();
        Field<Integer> SHARD_COUNT = Fields.intField("shard_count").makeOptional();
        Field<Integer> PART_COUNT = Fields.intField("part_count").makeOptional();
    }
}
