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.HiddenTableType;
import de.avatic.lcc.repositories.rates.ValidityPeriodRepository;
import de.avatic.lcc.service.bulk.helper.HeaderCellStyleProvider;
import de.avatic.lcc.service.excelMapper.*;
import de.avatic.lcc.util.exception.base.InternalErrorException;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.SheetVisibility;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

@Service
public class BulkExportService {

    private final HeaderCellStyleProvider headerCellStyleProvider;
    private final ContainerRateExcelMapper containerRateExcelMapper;
    private final ValidityPeriodRepository validityPeriodRepository;
    private final MatrixRateExcelMapper matrixRateExcelMapper;
    private final MaterialExcelMapper materialExcelMapper;
    private final PackagingExcelMapper packagingExcelMapper;
    private final NodeExcelMapper nodeExcelMapper;
    private final HiddenNodeExcelMapper hiddenNodeExcelMapper;
    private final HiddenCountryExcelMapper hiddenCountryExcelMapper;
    private final String sheetPassword;

    public BulkExportService(@Value("${lcc.bulk.sheet_password}") String sheetPassword, HeaderCellStyleProvider headerCellStyleProvider, ContainerRateExcelMapper containerRateExcelMapper, ValidityPeriodRepository validityPeriodRepository, MatrixRateExcelMapper matrixRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, HiddenNodeExcelMapper hiddenNodeExcelMapper, HiddenCountryExcelMapper hiddenCountryExcelMapper) {
        this.headerCellStyleProvider = headerCellStyleProvider;
        this.containerRateExcelMapper = containerRateExcelMapper;
        this.validityPeriodRepository = validityPeriodRepository;
        this.matrixRateExcelMapper = matrixRateExcelMapper;
        this.materialExcelMapper = materialExcelMapper;
        this.packagingExcelMapper = packagingExcelMapper;
        this.nodeExcelMapper = nodeExcelMapper;
        this.hiddenNodeExcelMapper = hiddenNodeExcelMapper;
        this.hiddenCountryExcelMapper = hiddenCountryExcelMapper;
        this.sheetPassword = sheetPassword;
    }

    public InputStreamSource generateExport(BulkFileType bulkFileType) throws IOException {
        return generateExport(bulkFileType, validityPeriodRepository.getValidPeriodId().orElseThrow(() -> new InternalErrorException("No valid period found that is VALID")));
    }

    public InputStreamSource generateExport(BulkFileType bulkFileType, Integer periodId) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            Workbook workbook = new XSSFWorkbook();
            Sheet worksheet = workbook.createSheet(BulkFileTypes.valueOf(bulkFileType.name()).getSheetName());

            CellStyle style = headerCellStyleProvider.createHeaderCellStyle(workbook);

            //TODO: check if a parallel task is needed.


            if (bulkFileType.equals(BulkFileType.COUNTRY_MATRIX) || bulkFileType.equals(BulkFileType.NODE)) {
                var hiddenCountrySheet = workbook.createSheet(HiddenTableType.COUNTRY_HIDDEN_TABLE.getSheetName());
                hiddenCountryExcelMapper.fillSheet(hiddenCountrySheet, style);
                hiddenCountrySheet.protectSheet(sheetPassword);
                workbook.setSheetVisibility(workbook.getSheetIndex(hiddenCountrySheet), SheetVisibility.VERY_HIDDEN);
            } else if (bulkFileType.equals(BulkFileType.CONTAINER_RATE) || bulkFileType.equals(BulkFileType.PACKAGING)) {
                var hiddenNodeSheet = workbook.createSheet(HiddenTableType.NODE_HIDDEN_TABLE.getSheetName());
                hiddenNodeExcelMapper.fillSheet(hiddenNodeSheet, style, BulkFileType.PACKAGING.equals(bulkFileType));
                hiddenNodeSheet.protectSheet(sheetPassword);
                workbook.setSheetVisibility(workbook.getSheetIndex(hiddenNodeSheet), SheetVisibility.VERY_HIDDEN);
            }

            // Create headers based on the bulk file type
            switch (bulkFileType) {
                case CONTAINER_RATE:
                    containerRateExcelMapper.fillSheet(worksheet, style, periodId);
                    break;
                case COUNTRY_MATRIX:
                    matrixRateExcelMapper.fillSheet(worksheet, style, periodId);
                    break;
                case MATERIAL:
                    materialExcelMapper.fillSheet(worksheet, style);
                    break;
                case PACKAGING:
                    packagingExcelMapper.fillSheet(worksheet, style);
                    break;
                case NODE:
                    nodeExcelMapper.fillSheet(worksheet, style);
                    break;
            }

            // Return the Excel file as an InputStreamSource
            workbook.write(outputStream);
            return new ByteArrayResource(outputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException("Failed to generate template", e);
        }
    }
}
