package controllers;

import java.net.URL;
import java.time.LocalDate;
import java.util.AbstractMap.SimpleEntry;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;

import org.eclipse.jetty.util.log.Log;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;

import data.GuiMysql;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import parser.OddsPortal;
import tests.AddedScoringTest;
import tests.AnalysisBettDrawTester;
import tests.AnalysisBettTester;
import tests.AwayTeamWinTest;
import tests.AwayTests2;
import tests.BetOnDifference;
import tests.DrawTests2;
import tests.FibonacciDrawTest;
import tests.HomeDrawAwayTest;
import tests.HomeTeamWinTest;
import tests.HomeTests2;
import tests.LastResultsTest;
import tests.LeagueTablePositionTest;
import tests.PrioCountriesAll;
import tests.RelevanceTest;
import tests.TestClass;
import tests.recalcTest;

public class TestsController implements Initializable {

    @FXML
    AnchorPane basePane;
    @FXML
    AnchorPane testSettingsPanel;
    @FXML
    AnchorPane testResultsPanel;
    @FXML
    Button getResults;
    @FXML
    ScrollPane resultsPanel;
    @FXML
    DatePicker date;
    @FXML
    ComboBox<String> countrySelector;
    @FXML
    ComboBox<String> leagueSelector;
    @FXML
    TextField bettingLevel;
    @FXML
    TextField startingBank;
    @FXML
    TextField lookBack;
    @FXML
    TextField betMargin;
    @FXML
    Button calcBestValues;
    @FXML
    Button getLeagueInfoButton;
    @FXML
    Button getMoreLeagueInfoButton;
    @FXML
    Button topLeaguesTest;
    @FXML
    Button homeTest;
    @FXML
    Button drawTest;
    @FXML
    Button awayTest;
    @FXML
    Button homeDrawAwayTest;
    @FXML
    Button homeTeamTest;
    @FXML
    Button awayTeamTest;
    @FXML
    Button addedScoreTest;
    @FXML
    Button recalcTest;
    @FXML
    Button fibonacciDrawTest;

    @FXML
    VBox testPanelVBox;

    ObservableList<String> countries = FXCollections.observableArrayList();
    ObservableList<String> leagues = FXCollections.observableArrayList();

    private final List<SimpleEntry<Integer, String>> countriesList = Lists.newArrayList();
    private List<SimpleEntry<Integer, String>> leaguesList = Lists.newArrayList();
    private int mSportId;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        getResults.setDisable(true);
        basePane.setPrefWidth(0.0);
        basePane.setPrefHeight(0.0);

        VBox.setVgrow(testPanelVBox, Priority.ALWAYS);

        date.valueProperty()
                .addListener((ov, oldValue, newValue) -> getResults.setDisable(newValue.isAfter(LocalDate.now())));

        countrySelector.setItems(countries);
        leagueSelector.setItems(leagues);
        testSettingsPanel.setVisible(false);
    }

    @FXML
    void getLeagueInfo() {
        final String country = countrySelector.getValue().trim();
        final String league = leagueSelector.getValue().trim();
        final OddsPortal op = new OddsPortal();
        op.getHistoricMatches("soccer", country, league, String.valueOf(LocalDate.now().getYear()));
    }

    @FXML
    private void addedScoreTestAction() {
        final AddedScoringTest test = new AddedScoringTest();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void analysisDrawTests() {
        final TestClass test = new AnalysisBettDrawTester();
        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
                -1, GuiMysql.getInstance().getSportId("soccer"),
                getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void analysisTets() {
        final TestClass test = new AnalysisBettTester();

        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
                -1, GuiMysql.getInstance().getSportId("soccer"),
                getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void awayTeamTestAction() {
        final AwayTeamWinTest test = new AwayTeamWinTest();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void awayTestAction() {
        final AwayTests2 test = new AwayTests2();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void calcBestResultsAction() {
        final LastResultsTest test = new LastResultsTest();

        calcBestValues.setDisable(true);
        final String buttonText = calcBestValues.getText();
        Platform.runLater(() -> {
            calcBestValues.setText("RUNNING...");
            test.calcBestResults(mSportId, getCountryIdFromSelector(), getLeagueIdFromSelector());
            calcBestValues.setDisable(false);

            calcBestValues.setText(buttonText);
        });
    }

    @FXML
    private void countrySelected(ActionEvent event) {
        if (countrySelector.getValue() != null && !countrySelector.getValue().equals("Country")) {
            leagueSelector.setDisable(false);
            final int countryId = getCountryIdFromSelector();
            final int sportId = getSoccerId();

            leaguesList = GuiMysql.getInstance().getLeaguesByDate(sportId, countryId, date.getValue().toString());

            leagues.clear();
            leagues.add("League");
            leaguesList.forEach(l -> leagues.add(l.getValue()));
        }
    }

    @FXML
    private void drawTestAction() {
        final DrawTests2 test = new DrawTests2();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void fibonacciDrawTestAction() {
        final TestClass test = new FibonacciDrawTest();

        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
                -1, GuiMysql.getInstance().getSportId("soccer"),
                getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    private String getBetLevel() {
        String betLevel = Strings.isNullOrEmpty(bettingLevel.getText()) ? bettingLevel.getPromptText()
                : bettingLevel.getText();
        betLevel = betLevel.replace("%", "").trim();
        return betLevel;
    }

    private String getBetMargin() {
        String betM = Strings.isNullOrEmpty(betMargin.getText()) ? betMargin.getPromptText() : betMargin.getText();
        betM = betM.replace("%", "").trim();
        return betM;
    }

    private Integer getCountryIdFromSelector() {
        Optional<SimpleEntry<Integer, String>> o = countriesList.stream()
                .filter(p -> p.getValue().equals(countrySelector.getValue())).findFirst();
        return o.isPresent() ? o.get().getKey() : null;
    }

    private Integer getLeagueIdFromSelector() {
        Optional<SimpleEntry<Integer, String>> o = leaguesList.stream()
                .filter(p -> p.getValue().equals(leagueSelector.getValue())).findFirst();
        return o.isPresent() ? o.get().getKey() : null;
    }

    private String getLookback() {
        return Strings.isNullOrEmpty(lookBack.getText()) ? lookBack.getPromptText() : lookBack.getText();
    }

    @FXML
    private void getMoreLeagueInfo() {
        final String lastParsedYear = GuiMysql.getInstance().getLastParsedYear(leagueSelector.getValue().trim(),
                getCountryIdFromSelector());
        final String nextParseYear;
        if (lastParsedYear.contains("-")) {
            final String[] years = lastParsedYear.split("-");
            int firstYear = Integer.parseInt(years[0]);
            int lastYear = Integer.parseInt(years[1]);
            firstYear--;
            lastYear--;
            nextParseYear = firstYear + "-" + lastYear;
        } else if (lastParsedYear.length() == 4) {
            Integer val = Integer.valueOf(lastParsedYear);
            val--;
            nextParseYear = String.valueOf(val);
        } else {
            Log.getLog().info("Fail to get More league info for %s", lastParsedYear);
            return;
        }

        final String country = countrySelector.getValue().trim();
        final String league = leagueSelector.getValue().trim();

        final OddsPortal op = new OddsPortal();
        op.getHistoricMatches("soccer", country, league, nextParseYear);
    }

    @FXML
    private void getResults() {
        countriesList.clear();
        leaguesList.clear();
        initCountries();
    }

    private int getSoccerId() {
        if (mSportId <= 0) {
            mSportId = GuiMysql.getInstance().getSportId(MainController.SPORT);
        }

        return mSportId;
    }

    private String getStartingBank() {
        return Strings.isNullOrEmpty(startingBank.getText()) ? startingBank.getPromptText() : startingBank.getText();
    }

    @FXML
    private void goalDiffTest() {
        final TestClass test = new BetOnDifference();

        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
                -1, GuiMysql.getInstance().getSportId("soccer"),
                getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void homeDrawAwayTestAction() {
        final HomeDrawAwayTest test = new HomeDrawAwayTest();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void homeTeamTestAction() {
        final HomeTeamWinTest test = new HomeTeamWinTest();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void homeTestAction() {
        final HomeTests2 test = new HomeTests2();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    private void initCountries() {
        countrySelector.setDisable(false);
        final int sportId = getSoccerId();

        countriesList.clear();
        countriesList.addAll(GuiMysql.getInstance().getCountriesBySport(sportId, date.getValue().toString()));

        countriesList.forEach(c -> countries.add(c.getValue()));
    }

    @FXML
    private void leagueSelected(ActionEvent event) {

        if (GuiMysql.getInstance().getParsingStarted(getCountryIdFromSelector(), getLeagueIdFromSelector())) {
            getLeagueInfoButton.setDisable(true);
            getMoreLeagueInfoButton.setDisable(false);
        } else {
            getLeagueInfoButton.setDisable(false);
            getMoreLeagueInfoButton.setDisable(true);
        }
        testSettingsPanel.setVisible(true);
    }

    @FXML
    private void recalcTestAction() {
        final recalcTest test = new recalcTest();

        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                Integer.valueOf(getLookback()),
                1, getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void relevanceTest() {
        final TestClass test = new RelevanceTest();

        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
                -1, GuiMysql.getInstance().getSportId("soccer"),
                getCountryIdFromSelector(), getLeagueIdFromSelector());

        test.runTest();
    }

    @FXML
    private void runTestAction() {

        final String betLevel = getBetLevel();
        final String betM = getBetMargin();
        final String startBank = getStartingBank();
        final String lookBackVal = getLookback();

        final TestClass test = new LastResultsTest();
        test.setup(date.getValue().toString(), Float.valueOf(startBank), Float.valueOf(betLevel), Float.valueOf(betM),
                Integer.valueOf(lookBackVal),
                mSportId, getCountryIdFromSelector(), getLeagueIdFromSelector());
        test.runTest();
    }

    @FXML
    private void standingsTest() {
        final TestClass test = new LeagueTablePositionTest();

        test.runTest();
    }

    @FXML
    private void topLeaguesTestAction() {
        final PrioCountriesAll prioCountriesAll = new PrioCountriesAll();
        prioCountriesAll.runTest();
    }
}
