package com.iqser.red.service.persistence.management.v1.processor.dataexchange.service;

import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.BaseDictionaryEntry;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity;
import com.iqser.red.service.persistence.management.v1.processor.dataexchange.ExportFilename;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.utils.FileSystemBackedArchiver;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type;

import io.micrometer.observation.annotation.Observed;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class EntityTypeExportService {

    static String JSON_EXT = ".json";
    static String TXT_EXT = ".txt";

    ObjectMapper mapper;
    EntryPersistenceService entryPersistenceService;

    @Observed(name = "EntityTypeExportService", contextualName = "export-entity-type")
    public void addEntityTypeToArchive(FileSystemBackedArchiver fileSystemBackedArchiver, TypeEntity typeEntity, String folder) throws JsonProcessingException {

        fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(resolveFolder(folder, typeEntity.getType()),
                                                                                      buildFilename(ExportFilename.DOSSIER_TYPE, JSON_EXT),
                                                                                      mapper.writeValueAsBytes(convert(typeEntity, Type.class))));

        List<? extends BaseDictionaryEntry> entriesList = entryPersistenceService.getEntries(typeEntity.getId(), DictionaryEntryType.ENTRY, null);

        List<String> entriesValueList = entriesList.stream()
                .filter(entry -> !entry.isDeleted())
                .map(BaseDictionaryEntry::getValue)
                .collect(Collectors.toList());

        List<String> deletedEntriesValueList = entriesList.stream()
                .filter(BaseDictionaryEntry::isDeleted)
                .map(BaseDictionaryEntry::getValue)
                .collect(Collectors.toList());

        List<? extends BaseDictionaryEntry> falsePositiveList = entryPersistenceService.getEntries(typeEntity.getId(), DictionaryEntryType.FALSE_POSITIVE, null);

        List<String> falsePositiveValuesList = falsePositiveList.stream()
                .filter(entry -> !entry.isDeleted())
                .map(BaseDictionaryEntry::getValue)
                .collect(Collectors.toList());

        List<String> deletedFalsePositiveValuesList = falsePositiveList.stream()
                .filter(BaseDictionaryEntry::isDeleted)
                .map(BaseDictionaryEntry::getValue)
                .collect(Collectors.toList());

        List<? extends BaseDictionaryEntry> falseRecommendationList = entryPersistenceService.getEntries(typeEntity.getId(), DictionaryEntryType.FALSE_RECOMMENDATION, null);

        List<String> falseRecommendationValuesList = falseRecommendationList.stream()
                .filter(entry -> !entry.isDeleted())
                .map(BaseDictionaryEntry::getValue)
                .collect(Collectors.toList());

        List<String> deletedFalseRecommendationValuesList = falseRecommendationList.stream()
                .filter(BaseDictionaryEntry::isDeleted)
                .map(BaseDictionaryEntry::getValue)
                .collect(Collectors.toList());

        writeEntriesListToFile(fileSystemBackedArchiver, entriesValueList, resolveFolder(folder, typeEntity.getType()), buildFilename(ExportFilename.ENTRIES, TXT_EXT));
        writeEntriesListToFile(fileSystemBackedArchiver,
                               deletedEntriesValueList,
                               resolveFolder(folder, typeEntity.getType()),
                               buildFilename(ExportFilename.DELETED_ENTRIES, TXT_EXT));
        writeEntriesListToFile(fileSystemBackedArchiver,
                               falsePositiveValuesList,
                               resolveFolder(folder, typeEntity.getType()),
                               buildFilename(ExportFilename.FALSE_POSITIVES, TXT_EXT));
        writeEntriesListToFile(fileSystemBackedArchiver,
                               deletedFalsePositiveValuesList,
                               resolveFolder(folder, typeEntity.getType()),
                               buildFilename(ExportFilename.DELETED_FALSE_POSITIVES, TXT_EXT));
        writeEntriesListToFile(fileSystemBackedArchiver,
                               falseRecommendationValuesList,
                               resolveFolder(folder, typeEntity.getType()),
                               buildFilename(ExportFilename.FALSE_RECOMMENDATION, TXT_EXT));
        writeEntriesListToFile(fileSystemBackedArchiver,
                               deletedFalseRecommendationValuesList,
                               resolveFolder(folder, typeEntity.getType()),
                               buildFilename(ExportFilename.DELETED_FALSE_RECOMMENDATION, TXT_EXT));
    }


    private static String resolveFolder(String folder, String name) {

        if (folder == null) {
            return name;
        }
        return folder + "/" + name;
    }


    private String buildFilename(ExportFilename exportFilename, String extension) {

        return exportFilename.getFilename() + extension;
    }


    private void writeEntriesListToFile(FileSystemBackedArchiver fileSystemBackedArchiver, List<String> entriesValuesList, String folderName, String filename) {

        try (ByteArrayOutputStream bt = new ByteArrayOutputStream(); //
             OutputStreamWriter osw = new OutputStreamWriter(bt, StandardCharsets.UTF_8); //
             BufferedWriter writer = new BufferedWriter(osw)) {

            Iterator<String> iterator = entriesValuesList.iterator();

            while (iterator.hasNext()) {
                String entry = iterator.next();
                writer.write(entry);

                if (iterator.hasNext()) {
                    writer.newLine();
                }
            }
            writer.flush();

            fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(folderName, filename, bt.toByteArray()));
        } catch (IOException e) {
            log.debug("Error writing values to files");
        }
    }

}
