package no.valg.valgnatt.frontend;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;

import no.valg.valgnatt.common.ValgnattException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * Klassen tilbyr en wrapper til det å lese/lagre rapportsamlinger.
 */
class RapportSamlingslager {

	static final String DATALAGRINGSOMRÅDE = "jboss.server.data.dir";
	private static final String VALGFILER_I_21ÅRHUNDRE = "^20\\d\\d(-nullrapporter)?.json$";
	private static final Logger LOG = LogManager.getLogger(RapportSamlingslager.class);

	private RapportSamlingslager() {

	}

	static void lagre(RapportSamling rapportSamling) throws IOException {
		LOG.info("Lagrer rapportsamling: " + rapporterPath(rapportSamling.getValgår(), rapportSamling.nullRapporter()).getFileName());
		Files.write(rapporterPath(rapportSamling.getValgår(), rapportSamling.nullRapporter()), rapportSamling.hentRapportSamlingJson().getBytes("UTF-8"));
	}

	private static Path rapporterPath(int valgår, boolean nullRapporter) {
		return Paths.get(System.getProperty(DATALAGRINGSOMRÅDE) + File.separator + valgår + (nullRapporter ? "-nullrapporter" : "") + ".json");
	}

	static void navngiVanligRapportSlikAtDenIkkeLengerBlirFunnet(int valgår) throws IOException {
		Path rapport = rapporterPath(valgår, false);
		if (Files.exists(rapport)) {
			String tmsStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"));
			Path target = rapport.resolveSibling(valgår + "-" + tmsStr + ".json");
			Files.move(rapport, target);
			LOG.info("Gir " + rapport.getFileName() + " nytt navn (" + target.getFileName() + ") fordi vi har innført sperrefrist og ikke lenger skal vises resultater");
		}
	}

	static RapportSamling les(int valgår, boolean nullRapporter) {

		Path path = rapporterPath(valgår, nullRapporter);
		try {
			RapportSamling rs = new RapportSamling(new String(Files.readAllBytes(path), "UTF-8"), false);
			LOG.info("Fant rapportsamling: " + path.getFileName());
			return rs;
		} catch (IOException ioe) {
			if (!nullRapporter) {
				LOG.info("Forsøker å finne nullrapporten for " + valgår + ", fordi vi ikke har noen annen rapport tilgjengelig. Dette kan skje når vi endrer fra sperrefrist til publisering, før vi har mottatt nye rapporter");
				return les(valgår, true);
			} else {
				LOG.warn("Fant ikke rapportsamling: " + path.getFileName() + ", hvilket betyr at vi ikke får lastet inn noe for dette valgåret. Evt. kommer data fra backend på et senere tidspunkt.");
				LOG.debug(ioe); // Vi ønsker aldri å se denne, men må gjøre det pga Sonar-kvalitetssjekker
				return null;
			}
		}
	}

	static Integer finnValgårSomHarNullrapportOgIkkeVanligRapport() {
		Integer gjeldendeValgår = null;
		for (int valgår : lagredeValgår()) {
			Path vanligRapport = rapporterPath(valgår, false);
			Path nullRapport = rapporterPath(valgår, true);
			if (Files.exists(nullRapport) && Files.notExists(vanligRapport)) {
				if (gjeldendeValgår == null) {
					gjeldendeValgår = valgår;
				} else {
					throw new ValgnattException("Du har minst 2 valgår som fremstår som gjeldende valgår (" + gjeldendeValgår + " og " + valgår + ").");
				}
			}
		}
		LOG.info("Fant at " + gjeldendeValgår + " er gjeldende valgår fordi man har nullrapporter men ikke vanlige rapporter, vil derfor laste nullrapporter inn i cache");
		return gjeldendeValgår;
	}

	static Set<Integer> lagredeValgår() {
		Set<Integer> valgårListe = new TreeSet<>();
		File[] filer = new File(System.getProperty(DATALAGRINGSOMRÅDE)).listFiles();
		for (File f : filer == null ? new File[]{} : filer) {
			if (Pattern.compile(VALGFILER_I_21ÅRHUNDRE).matcher(f.getName()).matches()) {
				valgårListe.add(Integer.parseInt(f.getName().substring(0, 4)));
			}
		}
		return valgårListe;
	}


}
