package de.avatic.lcc.service.bulk;

import de.avatic.lcc.dto.bulk.BulkFileType;
import de.avatic.lcc.model.bulk.BulkFileTypes;
import de.avatic.lcc.model.bulk.BulkOperation;
import de.avatic.lcc.service.api.BatchGeoApiService;
import de.avatic.lcc.service.bulk.bulkImport.*;
import de.avatic.lcc.service.excelMapper.*;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

@Service
public class BulkImportService {

    private final MatrixRateExcelMapper matrixRateExcelMapper;
    private final ContainerRateExcelMapper containerRateExcelMapper;
    private final MaterialExcelMapper materialExcelMapper;
    private final PackagingExcelMapper packagingExcelMapper;
    private final NodeExcelMapper nodeExcelMapper;

    private final NodeBulkImportService nodeBulkImportService;
    private final PackagingBulkImportService packagingBulkImportService;
    private final MaterialBulkImportService materialBulkImportService;
    private final MatrixRateImportService matrixRateImportService;
    private final ContainerRateImportService containerRateImportService;
    private final BatchGeoApiService batchGeoApiService;
    private final MaterialFastExcelMapper materialFastExcelMapper;

    public BulkImportService(MatrixRateExcelMapper matrixRateExcelMapper, ContainerRateExcelMapper containerRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, NodeBulkImportService nodeBulkImportService, PackagingBulkImportService packagingBulkImportService, MaterialBulkImportService materialBulkImportService, MatrixRateImportService matrixRateImportService, ContainerRateImportService containerRateImportService, BatchGeoApiService batchGeoApiService, MaterialFastExcelMapper materialFastExcelMapper) {
        this.matrixRateExcelMapper = matrixRateExcelMapper;
        this.containerRateExcelMapper = containerRateExcelMapper;
        this.materialExcelMapper = materialExcelMapper;
        this.packagingExcelMapper = packagingExcelMapper;
        this.nodeExcelMapper = nodeExcelMapper;
        this.nodeBulkImportService = nodeBulkImportService;
        this.packagingBulkImportService = packagingBulkImportService;
        this.materialBulkImportService = materialBulkImportService;
        this.matrixRateImportService = matrixRateImportService;
        this.containerRateImportService = containerRateImportService;
        this.batchGeoApiService = batchGeoApiService;
        this.materialFastExcelMapper = materialFastExcelMapper;
    }

    public void processOperation(BulkOperation op) throws IOException {
        var file = op.getFile();
        var type = op.getFileType();

        // Use FastExcel for MATERIAL, Apache POI for others
        if (type.equals(BulkFileType.MATERIAL)) {
            processOperationWithFastExcel(op);
        } else {
            processOperationWithApachePOI(op);
        }
    }

    private void processOperationWithFastExcel(BulkOperation op) throws IOException {
        var materials = materialFastExcelMapper.importFromExcel(op.getFile());
        materials.forEach(materialBulkImportService::processMaterialInstructions);
    }

    private void processOperationWithApachePOI(BulkOperation op) throws IOException {

        var file = op.getFile();
        var type = op.getFileType();

        InputStream in = new ByteArrayInputStream(file);

        try (Workbook workbook = new XSSFWorkbook(in)) {
            Sheet sheet = workbook.getSheet(BulkFileTypes.valueOf(type.name()).getSheetName());

            if (sheet == null) {

                BulkFileTypes foundType = findSheetType(workbook.getSheetAt(0));

                if(foundType != null && !foundType.equals(BulkFileTypes.valueOf(type.name())))
                    throw new ExcelValidationError("Unable to import " + op.getFileType().getFileType() + ", because " + foundType.getSheetName() + " template was found");

                throw new ExcelValidationError("Unable to import " + op.getFileType().getFileType() + ", because \"" + BulkFileTypes.valueOf(type.name()).getSheetName() + "\" sheet is missing. Please use correct template.");

            }

            switch (type) {
                case CONTAINER_RATE:
                    var containerRates = containerRateExcelMapper.extractSheet(sheet);
                    containerRateImportService.processContainerRates(containerRates);
                    break;
                case COUNTRY_MATRIX:
                    var matrixRates = matrixRateExcelMapper.extractSheet(sheet);
                    matrixRateImportService.processMatrixRates(matrixRates);
                    break;
//                case MATERIAL:
//                    var materials = materialExcelMapper.extractSheet(sheet);
//                    materials.forEach(materialBulkImportService::processMaterialInstructions);
//                    break;
                case PACKAGING:
                    var packaging = packagingExcelMapper.extractSheet(sheet);
                    packaging.forEach(packagingBulkImportService::processPackagingInstructions);
                    break;
                case NODE:
                    var nodeInstructions = nodeExcelMapper.extractSheet(sheet);
                    batchGeoApiService.geocodeBatch(nodeInstructions);
                    nodeInstructions.forEach(nodeBulkImportService::processNodeInstructions);
                    break;
                default:

            }
        } catch (RecordFormatException e) {
            throw new ExcelValidationError("Unable to open excel file. File is too large.");
        }

    }

    private BulkFileTypes findSheetType(Sheet sheet) {

        if(containerRateExcelMapper.isSheet(sheet))
            return BulkFileTypes.CONTAINER_RATE;

        if(matrixRateExcelMapper.isSheet(sheet))
            return BulkFileTypes.COUNTRY_MATRIX;

        if(materialExcelMapper.isSheet(sheet))
            return BulkFileTypes.MATERIAL;

        if(packagingExcelMapper.isSheet(sheet))
            return BulkFileTypes.PACKAGING;

        if(nodeExcelMapper.isSheet(sheet))
            return BulkFileTypes.NODE;

        return null;
    }


}
