package persistence;

import persistence.csv.CSVSerializable;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class GenericCSVDAO<T extends CSVSerializable> implements GenericDAO<T> {

	private final File file;
	private final Function<String[], T> constructor;

	public GenericCSVDAO(File file, Function<String[], T> constructor) {
		this.file = file;
		this.constructor = constructor;
		createFileIfMissing();
	}

	private void createFileIfMissing() {
		if (file.exists()) return;
		try {
			file.createNewFile();
		}
		catch (IOException e) {
			throw new PersistenceError("Could not create the file " + file.getAbsolutePath());
		}
	}

	public Set<T> getAll() {
		var lines = new ArrayList<String>();
		try (BufferedReader br = new BufferedReader(new FileReader(this.file))) {
			for (String line; (line = br.readLine()) != null; ) {
				lines.add(line);
			}
		}
		catch (IOException e) {
			throw new PersistenceError("Something went wrong while reading from file " + file.getAbsolutePath());
		}

		return lines
				.stream()
				.map(line -> constructor.apply(line.split(CSVSerializable.seperator)))
				.collect(Collectors.toSet());
	}

	@Override
	public void remove(T value) {
		var allEntities = this.getAll();
		this.removeAll();

		allEntities.stream().filter(entity -> !entity.equals(value)).forEach(this::add);
	}

	@Override
	public void add(T value) {
		try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(this.file, true))) {
			bufferedWriter.write(value.toCSVString());
			bufferedWriter.newLine();
		}
		catch (IOException e) {
			throw new PersistenceError("Something went wrong while writing to file " + file.getAbsolutePath());
		}
	}

	public void removeAll() {

		try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(this.file, false))) {
			bufferedWriter.write("");
		}
		catch (IOException e) {
			throw new PersistenceError("Something went wrong while writing to file " + file.getAbsolutePath());
		}
	}
}
