/* 
    This file is a part of the SteamWar software.
    
    Copyright (C) 2020  SteamWar.de-Serverteam

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package de.steamwar.sql;

import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.SelectStatement;
import de.steamwar.sql.internal.Statement;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.sql.Timestamp;
import java.util.*;

import static java.time.temporal.ChronoUnit.SECONDS;

@AllArgsConstructor
public class EventFight implements Comparable<EventFight> {

    private static final Table<EventFight> table = new Table<>(EventFight.class);
    private static final SelectStatement<EventFight> byId = table.select(Table.PRIMARY);
    private static final SelectStatement<EventFight> allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC");
    private static final SelectStatement<EventFight> event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC");
    private static final Statement reschedule = table.update(Table.PRIMARY, "StartTime");
    private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis");
    private static final Statement setFight = table.update(Table.PRIMARY, "Fight");

    private static final Statement create = table.insertFields(true, "eventID", "startTime", "spielmodus", "map", "teamBlue", "teamRed", "spectatePort");
    private static final Statement update = table.update(Table.PRIMARY, "startTime", "spielModus", "map", "teamBlue", "teamRed", "spectatePort");
    private static final Statement delete = table.delete(Table.PRIMARY);

    @Getter
    private static final Queue<EventFight> fights = new PriorityQueue<>();

    public static EventFight get(int fightID) {
        return byId.select(fightID);
    }

    public static void loadAllComingFights() {
        fights.clear();
        fights.addAll(allComing.listSelect());
    }

    public static List<EventFight> getEvent(int eventID) {
        return event.listSelect(eventID);
    }

    public static EventFight create(int event, Timestamp from, String spielmodus, String map, int blueTeam, int redTeam, Integer spectatePort) {
        return get(create.insertGetKey(event, from, spielmodus, map, blueTeam, redTeam, spectatePort));
    }

    @Getter
    @Field
    private final int eventID;
    @Getter
    @Field(keys = {Table.PRIMARY}, autoincrement = true)
    private final int fightID;
    @Getter
    @Setter
    @Field
    private Timestamp startTime;
    @Getter
    @Setter
    @Field
    private String spielmodus;
    @Getter
    @Setter
    @Field
    private String map;
    @Getter
    @Setter
    @Field
    private int teamBlue;
    @Getter
    @Setter
    @Field
    private int teamRed;
    @Getter
    @Setter
    @Field(nullable = true)
    private Integer spectatePort;
    @Getter
    @Field(def = "0")
    private int ergebnis;
    @Field(nullable = true)
    private int fight;

    public void setErgebnis(int winner) {
        this.ergebnis = winner;
        setResult.update(winner, fightID);
    }

    public void setFight(int fight) {
        //Fight.FightID, not EventFight.FightID
        this.fight = fight;
        setFight.update(fight, fightID);
    }

    public boolean hasFinished() {
        return fight != 0 || ergebnis != 0;
    }

    public void reschedule() {
        startTime = Timestamp.from(new Date().toInstant().plus(30, SECONDS));
        reschedule.update(startTime, fightID);
    }

    @Override
    public int hashCode(){
        return fightID;
    }

    @Override
    public boolean equals(Object o){
        if(o == null)
            return false;
        if(!(o instanceof EventFight))
            return false;
        return fightID == ((EventFight) o).fightID;
    }

    @Override
    public int compareTo(EventFight o) {
        return startTime.compareTo(o.startTime);
    }

    public void update(Timestamp startTime, String spielmodus, String map, int teamBlue, int teamRed, Integer spectatePort) {
        update.update(startTime, spielmodus, map, teamBlue, teamRed, spectatePort, fightID);
        this.startTime = startTime;
        this.spielmodus = spielmodus;
        this.map = map;
        this.teamBlue = teamBlue;
        this.teamRed = teamRed;
        this.spectatePort = spectatePort;
    }

    public void delete() {
        delete.update(fightID);
    }
}
