package ru.nbch.indicsearchservice.service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.mutable.MutableLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;
import ru.nbch.indicsearchservice.aggregator.FileAggregator;
import ru.nbch.indicsearchservice.dto.request.AddSearchJobRequestDto;
import ru.nbch.indicsearchservice.dto.response.AddSearchJobResponseDto;
import ru.nbch.indicsearchservice.dto.response.JobStatusResponseDto;
import ru.nbch.indicsearchservice.exporter.ExcelExporter;
import ru.nbch.indicsearchservice.exporter.JsonExporter;
import ru.nbch.indicsearchservice.loader.FirstLevelTableLoader;

@Service
public class IndicSearchService {
    private static final Logger log = LoggerFactory.getLogger(IndicSearchService.class);

    private static final boolean IS_EXPORT_AS_EXCEL = false;

    private final List<FirstLevelTableLoader> tableLoaders;
    private final List<FileAggregator> fileAggregators;
    private final ExcelExporter excelExporter;
    private final JsonExporter jsonExporter;

    public IndicSearchService(List<FirstLevelTableLoader> tableLoaders,
                              List<FileAggregator> fileAggregators,
                              ExcelExporter excelExporter,
                              JsonExporter jsonExporter) {
        this.tableLoaders = tableLoaders;
        this.fileAggregators = fileAggregators;
        this.excelExporter = excelExporter;
        this.jsonExporter = jsonExporter;
    }

    public AddSearchJobResponseDto addSearchJob(AddSearchJobRequestDto request) {
        UUID taskId = UUID.randomUUID();

        StopWatch sw = new StopWatch();

        // Первый этап. Получение данных из БД и заполнение файлов
        log.info("First step started. Getting data from database and filling csv files");
        sw.start();

        Map<String, Path> tableFileMap = new ConcurrentHashMap<>();
        tableLoaders.parallelStream().forEach(tl -> tl.searchBy(
            taskId,
            request.getDataType(),
            request.getSearchParameter(),
            request.getSearchValue(),
            request.getMemberCode().substring(0, 6),
            tableFileMap
        ));

        sw.stop();
        log.info(sw.prettyPrint());
        sw = new StopWatch();

        // Второй этап. Объединение файлов в один
        log.info("Second step started. Aggregating table files into one.");
        sw.start();

        MutableLong rowCounter = new MutableLong();
        Path aggregatedFile = fileAggregators.stream().map(fa -> fa.aggregateFiles(
                taskId,
                request.getDataType(),
                request.getSearchParameter(),
                request.getSearchValue(),
                request.getMemberCode().substring(0, 6),
                tableFileMap,
                rowCounter))
            .findFirst()
            .orElse(null);

        sw.stop();
        log.info(sw.prettyPrint());
        sw = new StopWatch();

        for (Path tableFilePath : tableFileMap.values()) {
            try {
                Files.deleteIfExists(tableFilePath);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        // Третий этап. Экспорт агрегированного файла в JSON или XLSX
        log.info("Third step started. Exporting aggregated file into JSON/XLSX.");
        sw.start();

        if (!IS_EXPORT_AS_EXCEL) {
            jsonExporter.writeJsonFile(aggregatedFile, taskId);
        } else {
            excelExporter.writeExcelFile(aggregatedFile, taskId, rowCounter.longValue());
        }

        sw.stop();
        log.info(sw.prettyPrint());

//        try {
//            Files.deleteIfExists(aggregatedFile);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }

        return null;
    }

    public JobStatusResponseDto getJobStatus(Long id) {
        return null;
    }

    public ResponseEntity<?> export(Long id, String exportType) {
        return null;
    }
}
