package de.accso.flexinale.application.services;

import de.accso.flexinale.domain.dao.AbstractDao;
import de.accso.flexinale.domain.dao.KinoSaalDao;
import de.accso.flexinale.domain.model.Kino;
import de.accso.flexinale.domain.model.KinoSaal;
import de.accso.flexinale.shared_kernel.FlexinaleIllegalArgumentException;
import de.accso.flexinale.shared_kernel.Identifiable;
import jakarta.transaction.Transactional;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

@Transactional
public class KinoSaalUploadService extends AbstractExcelDataUploadService<KinoSaal> {
    private static final Logger LOGGER = LoggerFactory.getLogger(KinoSaalUploadService.class);

    private final KinoSaalDao kinoSaalDao;

    public KinoSaalUploadService(KinoSaalDao kinoSaalDao) {
        this.kinoSaalDao = kinoSaalDao;
    }

    @Override
    public AbstractDao<KinoSaal> getDao() {
        return kinoSaalDao;
    }

    @Override
    public String getNameOfExcelDataType() {
        return KinoSaal.class.getSimpleName();
    }

    @Override
    public KinoSaal createDataFromExcelRow(final Row excelRow) {
        String kinoSaalIdAsString = excelRow.getCell(0).getStringCellValue();

        Identifiable.Id kinoId = Identifiable.Id.of(excelRow.getCell(3).getStringCellValue());

        Cell cellAnzahlPlaetze = excelRow.getCell(2);
        int anzahlPlaetze =
                switch(cellAnzahlPlaetze.getCellType()) {
                    case NUMERIC -> (int) cellAnzahlPlaetze.getNumericCellValue();
                    case STRING  -> Integer.parseInt(cellAnzahlPlaetze.getStringCellValue());
                    default -> throw new FlexinaleIllegalArgumentException("Anzahl Plaetze is not a number");
                };

        KinoSaal kinoSaal = new KinoSaal(
                Identifiable.Id.of(kinoSaalIdAsString),
                new KinoSaal.Name(excelRow.getCell(1).getStringCellValue()),
                new KinoSaal.AnzahlPlaetze(anzahlPlaetze),
                new Kino(kinoId)
        );

        LOGGER.debug("New KinoSaal created: " + kinoSaal);

        return kinoSaal;
    }

    public Map<Identifiable.Id, Collection<KinoSaal>> mapKinoSaeleToKino(final Collection<KinoSaal> kinoSaele) {
        Map<Identifiable.Id, Collection<KinoSaal>> saeleUndKinos = new HashMap<>();
        for (KinoSaal saal : kinoSaele) {
            Identifiable.Id key = saal.kino.id();

            Collection<KinoSaal> kinoSaeleAlreadyMapped = saeleUndKinos.get(key);
            if (kinoSaeleAlreadyMapped == null) {
                HashSet<KinoSaal> saele = new HashSet<>();
                saele.add(saal);
                saeleUndKinos.put(key, saele);
            }
            else {
                kinoSaeleAlreadyMapped.add(saal);
                saeleUndKinos.put(key, kinoSaeleAlreadyMapped);
            }
        }
        return saeleUndKinos;
    }
}
