package ru.yandex.webmaster3.storage.util.yt;

import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.web.util.UriComponentsBuilder;

/**
 * @author avhaliullin
 */
abstract class AbstractYtJob extends YtCommandImpl.PostCommand<YtOperationId> {
    private final String ytCluster;
    private final String commandName;
    private final List<YtPath> inputTables;
    private final List<YtPath> outputTables;
    private final Map<String, Object> secureVault;
    private final Map<String, Object> spec;

    AbstractYtJob(String commandName, String ytCluster, List<YtPath> inputTables, List<YtPath> outputTables,
                  Map<String, Object> secureVault, Map<String, Object> spec) {
        this.commandName = commandName;
        this.ytCluster = ytCluster;
        this.inputTables = inputTables;
        this.outputTables = outputTables;
        this.secureVault = secureVault;
        this.spec = spec;
    }

    @Override
    public boolean needHeavyProxy() {
        return false;
    }

    @Override
    protected UriComponentsBuilder createUri(URI proxyUri) {
        return UriComponentsBuilder.fromUri(proxyUri)
                .path(API_V3 + "/" + commandName);
    }

    public String getYtCluster() {
        return ytCluster;
    }

    protected Map<String, Object> getSpec() {
        HashMap<String, Object> result = new HashMap<>();
        fillSpec(result);
        return result;
    }

    protected void fillSpec(Map<String, Object> spec) {
        spec.putAll(this.spec);
        if (inputTables != null) {
            spec.put("input_table_paths", inputTables.stream().map(YtPath::toYtPath).collect(Collectors.toList()));
        }
        if (outputTables != null) {
            spec.put("output_table_paths", outputTables.stream().map(YtPath::toYtPath).collect(Collectors.toList()));
        }
        spec.put("secure_vault", secureVault);
    }

    @Override
    protected Object getYtParameters() {
        Map<String, Object> params = new HashMap<>();
        params.put("spec", getSpec());
        return params;
    }

    @Override
    protected YtResult<YtOperationId> onSuccess(YtStatus status, HttpResponse httpResponse) throws YtCommandException {
        HttpEntity entity = httpResponse.getEntity();
        if (entity == null) {
            return YtResult.createError(status, "Response is empty", null);
        }
        try {
            String id = EntityUtils.toString(entity);
            String operationId = YtService.OM.readValue(id, String.class);
            return YtResult.createResult(status, new YtOperationId(ytCluster, operationId));
        } catch (IOException e) {
            return YtResult.createError(status, "Unable to read response", e);
        }
    }

    @Override
    public String toString() {
        return commandName.toUpperCase() + " [" +
                inputTables.stream().map(YtPath::toYtPath).collect(Collectors.joining(", ")) +
                "] TO [" +
                outputTables.stream().map(YtPath::toYtPath).collect(Collectors.joining(", ")) +
                "] ON " + ytCluster;
    }
}
