package controllers;

import java.net.URL;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

import com.google.common.collect.Lists;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.layout.Pane;
import objects.HorseRaceData;
import parsers.AtgParser;
import parsers.TravsportParser;

@SuppressWarnings("rawtypes")
public class TestTabController extends AtgController {

	@FXML Pane DDButtonPane;
	@FXML Pane DDResultPane;
	@FXML DatePicker datePicker;
	@FXML Button getRacesButton;
	@FXML Button getRacesForDateButton;
	@FXML Button getRaceCalendarButton;
	@FXML ChoiceBox<String> raceTypeSelector;

	@FXML TableColumn<Map, Float> diffCalculationColumn = new TableColumn<>("Diff Calculated");
	@FXML TableColumn<Map, Float> diffPrevCalculationColumn = new TableColumn<>("Prev Diff Calculated");

	@FXML TableColumn<Map, Float> trendLast5DistColumn = new TableColumn<>("Trend last 5");
	@FXML TableColumn<Map, Float> trendLast5Column = new TableColumn<>("Trend last 5 Distance");

	@FXML private TableView<Map<String, Object>> racesTable;

	ObservableList<Map<String, Object>> tableRaces;
	ObservableList<String> raceTypes;

	@Override
	public void initialize(URL arg0, ResourceBundle arg1) {
		super.initialize(arg0, arg1);

		diffCalculationColumn.setCellValueFactory(new MapValueFactory<>("diffCalculated"));
		diffPrevCalculationColumn.setCellValueFactory(new MapValueFactory<>("diffPrevCalculatedValue"));
		trendLast5Column.setCellValueFactory(new MapValueFactory<>("trendLast5"));
		trendLast5DistColumn.setCellValueFactory(new MapValueFactory<>("trendLast5Distance"));

		raceTypes = FXCollections.observableArrayList();
		raceTypes.addAll(Lists.newArrayList("V75","dd","ld"));
		raceTypeSelector.setItems(raceTypes);

		datePicker.valueProperty().addListener((observable, oldValue, newValue) -> {
			if (newValue == null) {
				getRacesButton.setDisable(true);
				getRacesForDateButton.setDisable(true);
				getRaceCalendarButton.setDisable(true);
			} else if (newValue.isBefore(LocalDate.now())) {
				getRacesButton.setDisable(false);
				getRacesForDateButton.setDisable(false);
				getRaceCalendarButton.setDisable(false);
			} else if (newValue.isEqual(LocalDate.now())){
				getRacesButton.setDisable(false);
				getRacesForDateButton.setDisable(false);
				getRaceCalendarButton.setDisable(false);
			} else {
				//				getRacesButton.setDisable(true);
				//				getRacesForDateButton.setDisable(true);
			}
		});
	}

	@Override
	public void updateRacesTable() {
		super.updateRacesTable();

		final List<Integer> raceNumbers = todaysRaces.stream().map(m -> m.getRaceNumber()).distinct().collect(Collectors.toList());

		for (int i = 0; i < raceNumbers.size(); i++) {
			final int num = i;

			final ArrayList<String> distances = Lists.newArrayList();

			final List<HorseRaceData> races = todaysRaces.stream().filter(tr -> tr.getRaceNumber() == raceNumbers.get(num)).collect(Collectors.toList());
			final List<HorseRaceData> prevRaces = races.stream().collect(Collectors.toList());

			races.stream()
			.filter(hr -> hr.getRaceNumber() == prevRaces.get(0).getRaceNumber())
			.forEach(hr -> {
				if (!distances.contains(String.valueOf(hr.getDistance()))) {
					distances.add(String.valueOf(hr.getDistance()));
				}
			});

			prevRaces.sort((hr1, hr2) -> Float.compare(prevCalculation(hr1, getLaneWinPercent(hr1, distances)), prevCalculation(hr2, getLaneWinPercent(hr2, distances))));
			races.sort((hr1, hr2) -> Float.compare(calculatedValue(hr1, prevCalculation(hr1, getLaneWinPercent(hr1, distances))),
					calculatedValue(hr2, prevCalculation(hr2, getLaneWinPercent(hr2,distances)))));

			for (int j = 0; j < prevRaces.size() - 1; j++) {
				final HorseRaceData horseRaceData = prevRaces.get(j);
				todaysRaces.stream()
				.filter(ht -> ht.equals(horseRaceData))
				.findFirst().get()
				.setTimeToHorseBehindPrevCalculation(prevCalculation(prevRaces.get(j+1),getLaneWinPercent(prevRaces.get(j+1), distances)) -
						prevCalculation(horseRaceData,getLaneWinPercent(horseRaceData, distances)));
			}

			todaysRaces.stream().filter(ht -> ht.equals(prevRaces.get(prevRaces.size() -1))).findFirst().get().setTimeToHorseBehindPrevCalculation(999);

			for (int j = 0; j < races.size() - 1; j++) {
				final HorseRaceData horseRaceData = races.get(j);
				todaysRaces.stream()
				.filter(ht -> ht.equals(horseRaceData))
				.findFirst().get()
				.setTimeToHorseBehindCalculation(calculatedValue(races.get(j+1),prevCalculation(races.get(j+1), getLaneWinPercent(races.get(j+1), distances))) -
						calculatedValue(horseRaceData,prevCalculation(horseRaceData, getLaneWinPercent(horseRaceData, distances))));
			}

			todaysRaces.stream().filter(ht -> ht.equals(races.get(races.size() -1))).findFirst().get().setTimeToHorseBehindCalculation(999);

		}

		for (int i = 0; i < todaysRaces.size(); i++) {
			final Map<String, Object> currentRow = racesTable.getItems().get(i);
			final HorseRaceData horseRaceData = todaysRaces.get(i);

			final ArrayList<String> distances = Lists.newArrayList();
			todaysRaces.stream()
			.filter(hr -> hr.getRaceNumber() == horseRaceData.getRaceNumber())
			.forEach(hr -> { if (!distances.contains(String.valueOf(horseRaceData.getDistance()))) {
				distances.add(String.valueOf(hr.getDistance()));
			}
			});

			currentRow.put("diffPrevCalculatedValue", horseRaceData.getTimeToHorseBehindPrevCalculation());
			currentRow.put("diffCalculated", horseRaceData.getTimeToHorseBehindCalculation());
			//			System.out.println("Horse: " + horseRaceData.getHorseName() + " Driver: " + horseRaceData.getDriverName());
			Float laneWinPercent;
			try {
				if (horseRaceData.getTimeModifier().contains("a")) {
					laneWinPercent = DatabaseContoller.getInstance().getAutostartWinPercents(distances).get(horseRaceData.getLane()).getValue();
				} else {
					laneWinPercent = DatabaseContoller.getInstance().getVoltstartWinPercents(distances).get(horseRaceData.getLane()).getValue();
				}
			} catch (final IndexOutOfBoundsException e) {
				laneWinPercent = 0f;
			}
			currentRow.put("trendLast5", ((horseRaceData.getAvgHorseTimeByDistance() - (laneWinPercent / 8))));
		}

	}

	@FXML
	public void GetRacesAction() {
		todaysRaces = DatabaseContoller.getInstance().getTodaysRaces("", datePicker.getValue().toString());
		updateRacesTable();
	}

	@FXML
	public void GetRacesForDate() {
		System.out.println("Getting races for " + raceTypeSelector.getSelectionModel().getSelectedItem() + " at date " + datePicker.getValue().toString());
		resetLaneWinPercentages();
		AtgParser.getInstance().getStartsForDay(datePicker.getValue().toString(), raceTypeSelector.getSelectionModel().getSelectedItem());
		GetRacesAction();
	}

	public void GetRaceCalendar() {
		TravsportParser.getInstance().getRaceCalendar();
		//		AtgParser.getInstance().getResultsForDate(raceTypeSelector.getSelectionModel().getSelectedItem(), datePicker.getValue().toString());
		//		GetRacesAction();
	}
}
