package ru.yandex.webmaster3.storage.util.ydb.querybuilder;

import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import com.yandex.ydb.table.values.Type;
import com.yandex.ydb.table.values.Value;
import org.apache.commons.lang3.tuple.Pair;

import ru.yandex.webmaster3.storage.util.ydb.ExecuteQuery;
import ru.yandex.webmaster3.storage.util.ydb.query.Statement;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.ValueDataMapper;

/**
 * ishalaru
 * 01.02.2021
 **/
public abstract class BaseBatch<T> extends Statement {
    Collection<T> items;
    ValueDataMapper<T> valueDataMapper;
    private ExecuteQuery executeQuery;

    public BaseBatch(String tablePrefix, String table, OperationType operationType, ValueDataMapper<T> valueDataMapper, Collection<T> items, ExecuteQuery executeQuery) {
        super(tablePrefix, table, operationType);
        this.valueDataMapper = valueDataMapper;
        this.items = items;
        this.executeQuery = executeQuery;
    }


    @Override
    public String toQueryString() {
        StringBuilder sb = new StringBuilder(TABLE_PREFIX).append("'").append(tablePrefix).append("';\n");
        sb.append("DECLARE $data as \"List<Struct<\n");
        StringBuilder fields = new StringBuilder();
        final List<Pair<String, Type>> types = valueDataMapper.getTypes();
        for (Pair<String, Type> entry : types) {
            sb.append(entry.getLeft()).append(": ").append(entry.getRight().toString()).append(",");
            fields.append(entry.getKey()).append(",");
        }
        fields.setLength(fields.length() - 1);
        sb.setLength(sb.length() - 1);
        sb.append(">>\";\n");
        sb.append(operationDescription(table));
        sb.append("SELECT\n").append(fields).append("\n").append("FROM AS_TABLE($data);\n");
        return sb.toString();
    }

    protected abstract String operationDescription(String table);

    @Override
    public Map<String, Value> getParameters() {
        return Map.of("$data", valueDataMapper.convert(items));
    }

    public <T extends BaseBatch> T timeout(Duration timeout) {
        this.timeout = timeout;
        return (T) this;
    }

    public void execute() {
        this.executeQuery.execute(this);
    }

}
