/*
 *   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.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@AllArgsConstructor
public class Team {

    private static final Map<Integer, Team> teamCache = new HashMap<>();

    public static void clear() {
        teamCache.clear();
    }

    private static final Table<Team> table = new Table<>(Team.class);
    private static final SelectStatement<Team> byId = table.select(Table.PRIMARY);
    private static final SelectStatement<Team> byName = new SelectStatement<>(table, "SELECT * FROM Team WHERE (lower(TeamName) = ? OR lower(TeamKuerzel) = ?) AND NOT TeamDeleted");
    private static final SelectStatement<Team> all = table.selectFields("TeamDeleted");
    private static final Statement insert = table.insertFields("TeamKuerzel", "TeamName");
    private static final Statement update = table.update(Table.PRIMARY, "TeamKuerzel", "TeamName", "TeamColor", "Address", "Port");
    private static final Statement delete = table.update(Table.PRIMARY, "TeamDeleted");
    private static final Statement getSize = new Statement("SELECT COUNT(id) FROM UserData WHERE Team = ?");

    @Field(keys = {Table.PRIMARY}, autoincrement = true)
    @Getter
    private final int teamId;
    @Field
    @Getter
    private String teamKuerzel;
    @Field
    @Getter
    private String teamName;
    @Field(def = "'8'")
    @Getter
    private String teamColor;
    @Field(nullable = true)
    @Getter
    private String address;
    @Field(def = "'25565'")
    @Getter
    private int port;
    @Field(def = "0")
    private boolean teamDeleted;

    public static void create(String kuerzel, String name){
        insert.update(kuerzel, name);
    }

    public static Team get(int id) {
        return teamCache.computeIfAbsent(id, byId::select);
    }

    public static Team get(String name){
        // No cache lookup due to low frequency use
        name = name.toLowerCase();
        return byName.select(name, name);
    }

    public static List<Team> getAll(){
        clear();
        List<Team> teams = all.listSelect(false);
        teams.forEach(team -> teamCache.put(team.getTeamId(), team));
        return teams;
    }

    public List<Integer> getMembers(){
        return SteamwarUser.getTeam(teamId).stream().map(SteamwarUser::getId).collect(Collectors.toList());
    }

    public int size(){
        return getSize.select(rs -> {
            rs.next();
            return rs.getInt("COUNT(id)");
        }, teamId);
    }

    public void disband(SteamwarUser user){
        user.setLeader(false);
        delete.update(true, teamId);
        teamCache.remove(teamId);
        TeamTeilnahme.deleteFuture(teamId);
    }

    public void setTeamKuerzel(String teamKuerzel) {
        this.teamKuerzel = teamKuerzel;
        updateDB();
    }

    public void setTeamName(String teamName) {
        this.teamName = teamName;
        updateDB();
    }

    public void setTeamColor(String teamColor) {
        this.teamColor = teamColor;
        updateDB();
    }

    public void setAddress(String address) {
        this.address = address;
        updateDB();
    }

    public void setPort(int port) {
        this.port = port;
        updateDB();
    }

    private void updateDB(){
        update.update(teamKuerzel, teamName, teamColor, address, port, teamId);
    }
}
