package de.jeyp91.tippliga;

import com.google.api.client.util.DateTime;
import de.jeyp91.TeamIDMatcher;
import de.jeyp91.apifootball.APIFootballMatch;
import de.jeyp91.apifootball.APIFootballMatchesProvider;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;

public class TLWMatchesUpdaterFootball extends TLWMatchesManagerBase {

    ArrayList<TLWMatch> tlwMatchesOriginal;
    ArrayList<TLWMatch> tlwMatchesUpdated;

    public TLWMatchesUpdaterFootball(int season, int league, String configFileName) throws Exception {

        this.season = season;
        this.league = league;

        tlwMatchesOriginal = new ArrayList<>();
        tlwMatchesUpdated = new ArrayList<>();

        super.initConfigParamsFromFile(configFileName);
        this.initUpdates();
    }

    private void initUpdates() throws Exception {

        APIFootballMatchesProvider apiFootballMatchesProvider = new APIFootballMatchesProvider(this.season);
        TippligaSQLConnector tippligaSQLConnector = new TippligaSQLConnector();
        for (Object singleMatchdayConfig : this.matchdayConfig) {
            int tlwMatchday = ((Long) ((JSONObject) singleMatchdayConfig).get("TLWMatchday")).intValue();
            JSONArray matchesConfig = (JSONArray) ((JSONObject) singleMatchdayConfig).get("matchesConfig");

            ArrayList<APIFootballMatch> apiFootballMatches = apiFootballMatchesProvider.getAPIFootballMatchesFromConfig(matchesConfig);

            ArrayList<TLWMatch> tlwMatchesOriginalMatchday = tippligaSQLConnector.getMatches(String.valueOf(this.season), String.valueOf(this.league), String.valueOf(tlwMatchday));
            ArrayList<TLWMatch> tlwMatchesUpdatedMatchday = new ArrayList<>();
            for (TLWMatch match : tlwMatchesOriginalMatchday) tlwMatchesUpdatedMatchday.add(new TLWMatch(match));

            if (apiFootballMatches.size() > tlwMatchesUpdatedMatchday.size()) {
                throw new Exception("Not matching config!");
            }

            addMissingMatches(tlwMatchesUpdatedMatchday, apiFootballMatches);
            updateMatchDateTimes(tlwMatchesUpdatedMatchday, apiFootballMatches);
            updateStatus(tlwMatchesUpdatedMatchday);

            this.tlwMatchesOriginal.addAll(tlwMatchesOriginalMatchday);
            this.tlwMatchesUpdated.addAll(tlwMatchesUpdatedMatchday);
        }
    }

    public String getUpdateSQL() {
        return this.getUpdateString(tlwMatchesOriginal, tlwMatchesUpdated);
    }

    private String getUpdateString(ArrayList<TLWMatch> matchesOriginal, ArrayList<TLWMatch> matchesUpdated) {
        String updateString = "";
        for (int i = 0; i < matchesOriginal.size(); i++) {
            updateString += getUpdateString(matchesOriginal.get(i), matchesUpdated.get(i));
        }
        return updateString;
    }

    private String getUpdateString(TLWMatch matchOriginal, TLWMatch matchUpdated) {
        String updateString = "";
        String updateStart = "UPDATE phpbb_footb_matches SET ";
        String condition = "WHERE season = " + matchOriginal.getSeason() + " " +
                "AND league = " + matchOriginal.getLeague() + " " +
                "AND matchday = " + matchOriginal.getMatchday() + " " +
                "AND match_no = " + matchOriginal.getMatchNo() + ";\n";

        if(matchOriginal.getTeamIdHome() != matchUpdated.getTeamIdHome()) {
            updateString += updateStart +
                    "team_id_home = " + matchUpdated.getTeamIdHome() + " " +
                    condition;
        }

        if(matchOriginal.getTeamIdGuest() != matchUpdated.getTeamIdGuest()) {
            updateString += updateStart +
                    "team_id_guest = " + matchUpdated.getTeamIdGuest() + " " +
                    condition;
        }

        if (!matchOriginal.getMatchDateTime().equals(matchUpdated.getMatchDateTime())) {
            updateString += updateStart +
                    "match_datetime = '" + matchUpdated.getMatchDateTime() + "' " +
                    condition;
        }

        if (!matchOriginal.getStatus().equals(matchUpdated.getStatus())) {
            updateString += updateStart +
                    "status = '" + matchUpdated.getStatus() + "' " +
                    condition;
        }


        return updateString;
    }

    private void addMissingMatches(ArrayList<TLWMatch> tlwMatches,
                                   ArrayList<APIFootballMatch> apiFootballMatches) throws Exception {

        ArrayList<APIFootballMatch> missingMatches = new ArrayList<>();

        for(APIFootballMatch apiFootballMatch : apiFootballMatches) {
            if(getMatchingMatch(apiFootballMatch, tlwMatches) == null) {
                missingMatches.add(apiFootballMatch);
            }
        }

        for (APIFootballMatch missingMatch : missingMatches) {
            boolean done = false;
            for(TLWMatch tlwMatch : tlwMatches) {
                if(tlwMatch.getTeamIdHome() == 0 && tlwMatch.getTeamIdGuest() == 0) {
                    tlwMatch.updateMatch(missingMatch);
                    done = true;
                    break;
                }
            }
            if(!done) {
                throw new Exception("Could not add missing match");
            }
        }
    }

    private void updateMatchDateTimes(
            ArrayList<TLWMatch> tlwMatches,
            ArrayList<APIFootballMatch> apiFootballMatches) throws Exception
    {
        for(APIFootballMatch apiFootballMatch : apiFootballMatches) {
            TLWMatch tlwMatch = getMatchingMatch(apiFootballMatch, tlwMatches);
            tlwMatch.setMatchDateTime(apiFootballMatch.getMatchDateTime().replace("T", " ").substring(0, 19));
        }
    }

    private void updateStatus(ArrayList<TLWMatch> matches) {
        LocalDateTime earliestDate = TLWMatchesManagerBase.getFirstMatchtimeTLW(matches);
        LocalDateTime now = LocalDateTime.now();
        if(earliestDate.isAfter(now)) {
            for(TLWMatch match : matches) {
                LocalDateTime date = TLWMatchesManagerBase.getDate(match);
                if (this.getDaysDifference(earliestDate, date) == 0) {
                    match.setStatus(0);
                } else {
                    match.setStatus(-1);
                }
            }
        }
    }

    private TLWMatch getMatchingMatch(APIFootballMatch apiFootballMatch, ArrayList<TLWMatch> tlwMatches) throws Exception {
        int foundMatches = 0;
        TLWMatch matchingMatch = null;
        for(TLWMatch match : tlwMatches) {
            int apiTeamIdHome = TeamIDMatcher.getTippligaIdFromApiFootballId(apiFootballMatch.getTeamIdHome());
            int apiTeamIdGuest = TeamIDMatcher.getTippligaIdFromApiFootballId(apiFootballMatch.getTeamIdGuest());
            if(
                    apiTeamIdHome == match.getTeamIdHome()
                    && apiTeamIdGuest == match.getTeamIdGuest()
            ) {
                foundMatches++;
                matchingMatch = match;
            }
        }
        if(foundMatches > 1) {
            throw new Exception("Found more than one matching matches");
        }
        return matchingMatch;
    }

    public ArrayList<TLWMatch> getTLWMatchesUpdated() {
        return this.tlwMatchesUpdated;
    }
}
