package de.ivu.elect.core.exchange.wahlbeteiligung.csv;

import java.io.InputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.exchange.control.FileKonfiguration;
import de.ivu.elect.business.exchange.control.MappingException;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlauf;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlaufExchangeContext;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlaufGebiet;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlaufStatus;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlaufTK;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlaufTyp;
import de.ivu.elect.core.exchange.wahlbeteiligung.WahlbeteiligungVerlaufImportMapper;
import de.ivu.elect.core.exchange.wahlbeteiligung.xml.DefaulXmlWahlbeteiligungVerlaufExportMapper;
import de.ivu.elect.exchange.CsvImportMapper;
import de.ivu.elect.exchange.csv.CsvMarshaller;
import de.ivu.elect.exchange.gebietsbaum.mapper.GebietMapperUtil;
import de.ivu.elect.interfaces.core.GebietReferenz;
import de.ivu.elect.jee.exchange.Violations;

public class DefaultCsvWahlbeteiligungVerlaufImportMapper implements WahlbeteiligungVerlaufImportMapper, CsvImportMapper<List<WahlbeteiligungVerlauf>, WahlbeteiligungVerlaufExchangeContext> {

  public static final String DATE_PATTERN = "yyyy-MM-dd HH-mm-ss";

  @Inject
  private transient CsvMarshaller csvMarshaller;

  @Inject
  private transient GebietMapperUtil gebietMapperUtil;

  @Override
  public List<String> getCsvColumnHeaders(WahlbeteiligungVerlaufExchangeContext context) {
    return csvMarshaller.extractHeader(WahlbeteiligungVerlaufDTO.class);
  }

  @Override
  public List<WahlbeteiligungVerlauf> deserialize(InputStream is, WahlbeteiligungVerlaufExchangeContext wahlbeteiligungVerlaufExchangeContext, FileKonfiguration fileKonfiguration) throws MappingException {
    List<WahlbeteiligungVerlauf> result = new ArrayList<>();
    Map<GebietReferenz, Gebiet> gebietMap = new HashMap<>();

    WahlbeteiligungVerlauf wahlbeteiligungVerlauf = null;
    for (WahlbeteiligungVerlaufDTO wahlbeteiligungVerlaufDTO : csvMarshaller.deserialize(WahlbeteiligungVerlaufDTO.class, is, fileKonfiguration)) {
      WahlbeteiligungVerlaufTK wahlbeteiligungVerlaufTK = createWahlbeteiligungVerlaufTK(wahlbeteiligungVerlaufDTO);
      if (wahlbeteiligungVerlauf == null || !wahlbeteiligungVerlauf.getWahlbeteiligungVerlaufTK().equals(wahlbeteiligungVerlaufTK)) {
        wahlbeteiligungVerlauf = new WahlbeteiligungVerlauf();
        wahlbeteiligungVerlauf.setDatum(wahlbeteiligungVerlaufTK.getDatum());
        wahlbeteiligungVerlauf.setName(wahlbeteiligungVerlaufTK.getName());
        wahlbeteiligungVerlauf.setTyp(WahlbeteiligungVerlaufTyp.valueOf(wahlbeteiligungVerlaufDTO.getTyp()));
        wahlbeteiligungVerlauf.setStatus(WahlbeteiligungVerlaufStatus.IMPORTIERT);
        result.add(wahlbeteiligungVerlauf);
      }
      WahlbeteiligungVerlaufGebiet wahlbeteiligungVerlaufGebiet = createWahlbeteiligungVerlaufGebiet(wahlbeteiligungVerlaufDTO, gebietMap);
      wahlbeteiligungVerlaufGebiet.setWahlbeteiligungVerlauf(wahlbeteiligungVerlauf);
    }

    return result;
  }

  private WahlbeteiligungVerlaufGebiet createWahlbeteiligungVerlaufGebiet(WahlbeteiligungVerlaufDTO wahlbeteiligungVerlaufDTO, Map<GebietReferenz, Gebiet> gebietMap) {

    WahlbeteiligungVerlaufGebiet result = new WahlbeteiligungVerlaufGebiet();
    GebietReferenz gebietReferenz = createGebietReferenz(wahlbeteiligungVerlaufDTO);
    result.setGebiet(gebietMapperUtil.createGebiet(gebietReferenz, gebietMap));
    if (StringUtils.isNotBlank(wahlbeteiligungVerlaufDTO.getWahlbeteiligung())) {
      result.setWahlbeteilung(new BigDecimal(wahlbeteiligungVerlaufDTO.getWahlbeteiligung()));
    }

    return result;

  }

  private GebietReferenz createGebietReferenz(WahlbeteiligungVerlaufDTO wahlbeteiligungVerlaufDTO) {
    GebietReferenz gebietReferenz = new GebietReferenz();
    gebietReferenz.setGebietsart(wahlbeteiligungVerlaufDTO.getGebietArt());
    gebietReferenz.setNummer(wahlbeteiligungVerlaufDTO.getGebietNummer());
    return gebietReferenz;
  }

  private WahlbeteiligungVerlaufTK createWahlbeteiligungVerlaufTK(WahlbeteiligungVerlaufDTO wahlbeteiligungVerlaufDTO) {
    return new WahlbeteiligungVerlaufTK(parseDate(wahlbeteiligungVerlaufDTO), wahlbeteiligungVerlaufDTO.getWahlname());
  }

  private Date parseDate(WahlbeteiligungVerlaufDTO wahlbeteiligungVerlaufDTO) {
    try {
      return new SimpleDateFormat(DATE_PATTERN, Locale.GERMANY).parse(wahlbeteiligungVerlaufDTO.getZeitpunkt());
    } catch (ParseException e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }

  @Override
  public Violations validateInputFormat(InputStream is, WahlbeteiligungVerlaufExchangeContext wahlbeteiligungVerlaufExchangeContext, FileKonfiguration fileKonfiguration) {
    return new Violations();
  }

  @Override
  public FileFormat getFileFormat() {
    return new FileFormat(DefaulXmlWahlbeteiligungVerlaufExportMapper.FILE_FORMAT, FileType.CSV);
  }

  @Override
  public boolean isAcceptContext(WahlbeteiligungVerlaufExchangeContext wahlbeteiligungVerlaufExchangeContext) {
    return wahlbeteiligungVerlaufExchangeContext.getWahl() != null;
  }
}
