/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 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 java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@AllArgsConstructor
public class Fight {

    private static final Table<Fight> table = new Table<>(Fight.class);
    private static final SelectStatement<Fight> getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.Config & 2) AND (r.NodeId IS NULL OR r.Config & 2) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
    private static final SelectStatement<Fight> getById = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.Config & 2) AND (r.NodeId IS NULL OR r.Config & 2) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId WHERE FightId = ?");
    private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
    private static final Statement updateReplayAvailable = table.update(Table.PRIMARY, "ReplayAvailable");

    public static List<Fight> getPage(int page, int elementsPerPage) {
        List<Fight> fights = getPage.listSelect(page * elementsPerPage, elementsPerPage);

        List<FightPlayer> fightPlayers = FightPlayer.batchGet(fights.stream().map(f -> f.fightID));
        for(Fight fight : fights) {
            fight.initPlayers(fightPlayers);
        }

        SteamwarUser.batchCache(fightPlayers.stream().map(FightPlayer::getUserID).collect(Collectors.toSet()));
        return fights;
    }

    public static Fight getById(int fightID) {
        return getById.select(fightID);
    }

    public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){
        return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition);
    }

    public static void markReplayAvailable(int fightID) {
        updateReplayAvailable.update(true, fightID);
    }

    @Getter
    @Field(keys = {Table.PRIMARY}, autoincrement = true)
    private final int fightID;
    @Field
    private final String gameMode;
    @Getter
    @Field
    private final String server;
    @Getter
    @Field
    private final Timestamp startTime;
    @Field
    private final int duration;
    @Field
    private final int blueLeader;
    @Field
    private final int redLeader;
    @Field(nullable = true)
    private final Integer blueSchem;
    @Field(nullable = true)
    private final Integer redSchem;
    @Getter
    @Field
    private final int win;
    @Field
    private final String wincondition;
    @Field
    private final boolean replayAvailable;
    @Field // Virtual field for easy select
    private final boolean replayAllowed;

    @Getter
    private final List<FightPlayer> bluePlayers = new ArrayList<>();
    @Getter
    private final List<FightPlayer> redPlayers = new ArrayList<>();

    public SchematicType getSchemType() {
        return SchematicType.fromDB(gameMode);
    }

    public SteamwarUser getBlueLeader() {
        return SteamwarUser.get(blueLeader);
    }

    public SteamwarUser getRedLeader() {
        return SteamwarUser.get(redLeader);
    }

    public boolean replayAllowed() {
        return replayExists() && replayAllowed;
    }

    public boolean replayExists() {
        return getSchemType() != null && replayAvailable;
    }

    private void initPlayers(List<FightPlayer> fightPlayers) {
        for(FightPlayer fp : fightPlayers) {
            if(fp.getFightID() != fightID)
                continue;

            if(fp.getTeam() == 1)
                bluePlayers.add(fp);
            else
                redPlayers.add(fp);
        }
    }
}
