package org.micord.service;

import org.micord.enums.ConfigType;
import org.micord.models.requests.downloads.*;
import org.micord.models.requests.RequestParameters;
import org.micord.models.requests.Requests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class ApiService {

	private static final Logger logger = LoggerFactory.getLogger(ApiService.class);

	@Autowired
	private RequestService sqlAndAqlService;

	@Autowired
	private DownloadService downloadService;

	@Autowired
	private ConfigService configService;

	@Autowired
	private ValidationService validationService;

	public void process(ConfigType methodName, List<String> ids) throws FileNotFoundException, SQLException {
		Requests config = configService.getConfig(methodName, Requests.class);
		sqlAndAqlService.processSqlAndAqlRequests(config, ids);
	}

	public void process(ConfigType methodName, RequestParameters parameters) throws FileNotFoundException, SQLException {
		Requests config = configService.getConfig(methodName, Requests.class);
		sqlAndAqlService.processSqlAndAqlRequests(config, parameters);
	}

	public File download(ConfigType methodName, RequestParameters downloadRequest) throws IOException, SQLException {
		Requests config = configService.getConfig(methodName, Requests.class);

		String type = downloadRequest.getType();
		List<String> ids = Optional.ofNullable(downloadRequest.getIds())
			.filter(list -> !list.isEmpty())
			.orElse(null);

		BaseDownloadRequest selectedRequest = config.getAqlDownloadRequests().stream()
			.filter(r -> r.getDownloadRequestType().equals(type))
			.findFirst()
			.map(BaseDownloadRequest.class::cast)
			.or(() -> config.getSqlDownloadRequests().stream()
				.filter(r -> r.getDownloadRequestType().equals(type))
				.findFirst()
				.map(BaseDownloadRequest.class::cast))
			.orElseThrow(() -> new IllegalArgumentException("Invalid download type: " + type));

		Map<String, Boolean> validationResults = validationService.validateDownloadRequest(selectedRequest, downloadRequest, ids);

		return downloadService.download(selectedRequest, ids, downloadRequest, validationResults);
	}

	public List<String> getDownloadTypes(ConfigType methodName) throws FileNotFoundException {
		Requests config = configService.getConfig(methodName, Requests.class);

		return Stream.concat(
				Optional.ofNullable(config.getSqlDownloadRequests()).orElse(Collections.emptyList()).stream(),
				Optional.ofNullable(config.getAqlDownloadRequests()).orElse(Collections.emptyList()).stream()
			)
			.map(BaseDownloadRequest::getDownloadRequestType)
			.distinct()
			.collect(Collectors.toList());
	}

}
