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

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.storage.clickhouse.replication.data.ClickhouseReplicationCommand;
import ru.yandex.webmaster3.storage.clickhouse.replication.data.ClickhouseReplicationPriority;
import ru.yandex.webmaster3.storage.clickhouse.replication.data.ClickhouseReplicationState;
import ru.yandex.webmaster3.storage.clickhouse.replication.data.ClickhouseReplicationTaskGroup;
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;

/**
 * @author avhaliullin
 */
@Repository
public class ClickhouseReplicationQueueYDao extends AbstractYDao {

    public ClickhouseReplicationQueueYDao() {
        super(PREFIX_IMPORTER, "clickhouse_replication_queue");
    }

    public void update(ClickhouseReplicationTaskGroup taskGroup) {
        ClickhouseReplicationCommand command = taskGroup.getCommand();
        upsert(
                F.TASK_ID.value(command.getReplicationTaskId()),
                F.DATABASE.value(command.getDatabase()),
                F.PRIORITY.value(command.getPriority()),
                F.TABLES.value(command.getTables()),
                F.STATE.value(taskGroup.getState())
        ).execute();
    }

    public List<ClickhouseReplicationTaskGroup> listTasks() {
        List<ClickhouseReplicationTaskGroup> result = new ArrayList<>();
        streamReader(MAPPER, e -> result.add(e));
        return result;
    }

    public List<ClickhouseReplicationTaskGroup> listUnfinishedTasks() {
        return select(MAPPER).where(F.STATE.ne(ClickhouseReplicationState.DONE)).queryForList();
    }

    public void remove(ClickhouseReplicationTaskGroup taskGroup) {
        delete().where(F.TASK_ID.eq(taskGroup.getCommand().getReplicationTaskId())).execute();
    }

    public ClickhouseReplicationTaskGroup getTaskGroupState(UUID taskGroupId) {
        return select(MAPPER).where(F.TASK_ID.eq(taskGroupId)).queryOne();
    }

    private static final DataMapper<ClickhouseReplicationCommand> COMMAND_MAPPER = DataMapper.create(
            F.TASK_ID, F.DATABASE, F.PRIORITY, F.TABLES, ClickhouseReplicationCommand::new
    );

    private static final DataMapper<ClickhouseReplicationTaskGroup> MAPPER = DataMapper.create(
            COMMAND_MAPPER, F.STATE, ClickhouseReplicationTaskGroup::new
    );

    private interface F {
        Field<UUID> TASK_ID = Fields.uuidField("task_id");
        Field<String> DATABASE = Fields.stringField("database");
        Field<ClickhouseReplicationPriority> PRIORITY = Fields.stringEnumField("priority", ClickhouseReplicationPriority.R);
        Field<List<ClickhouseReplicationCommand.TableInfo>> TABLES = Fields.jsonField2("tables", ClickhouseReplicationCommand.TableInfo.LIST_REFERENCE);
        Field<ClickhouseReplicationState> STATE = Fields.stringEnumField("state", ClickhouseReplicationState.R);
    }
}
