package at.reisinger.server;

import at.reisinger.obj.*;
import at.reisinger.obj.Package;
import at.reisinger.server.helper.JsonHelper;
import at.reisinger.server.helper.PostgresHelper;

import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Stellt die Verbindung zur "Datenbank" her
 * Die "Datenbank" sind hier nur beispieldaten.
 */
public class DBConnection {
    private Connection c;
    private Statement stmt;


    /**
     * Erstellt alle Beispieldaten und simuliert somit den
     * Verbindungsaufbau zu einer DB
     */
    public DBConnection() {
        this.c = null;
    }

    /**
     * Erstellt alle Tabellen die für den Betrieb der Software bennötigt werden
     * @return True bei erfolg, sonst error
     */
    public boolean init() {
        ArrayList<Boolean> errors = new ArrayList<>();
        errors.add(PostgresHelper.executeUpdateMessage("CREATE TABLE IF NOT EXISTS USERS (username TEXT PRIMARY KEY NOT NULL, nachname TEXT NOT NULL, email TEXT NOT NULL, password TEXT NOT NULL, bio TEXT, image TEXT, coins integer default 20 not null)", "User Table created"));
        errors.add(PostgresHelper.executeUpdate("CREATE TABLE IF NOT EXISTS CARD(NAME TEXT not null,DAMAGE FLOAT not null,ELEMENTTYP TEXT not null,CARDTYPE TEXT not null, PRIMARY KEY (\"name\"));"));
        errors.add(PostgresHelper.executeUpdateMessage("create unique index IF NOT EXISTS card_name_uindex on CARD (NAME);", "Card Table created"));
        errors.add(PostgresHelper.executeUpdateMessage("create table IF NOT EXISTS package(\"ID\" varchar(255) not null,name varchar(255) not null constraint name references card, i serial not null constraint package_i primary key );", "Package Table created"));
        errors.add(PostgresHelper.executeUpdateMessage("create table IF NOT EXISTS user_cards(username TEXT not null constraint user_cards_users_username_fk references users,name text not null, gesperrt boolean not null);", "UserCards Table created"));
        errors.add(PostgresHelper.executeUpdateMessage("create table IF NOT EXISTS user_deck(username text not null constraint user_deck_users_username_fk references users,cardname text not null);", "UserDeck Table created"));
        errors.add(PostgresHelper.executeUpdateMessage("create table IF NOT EXISTS trading(username text not null constraint trading_users_username_fk references users,id text not null constraint trading_pk primary key, cardtotrade text not null constraint trading_card_name_fk references card, mindamage float not null,reqcardtype text not null,reqelement text not null);", "Trading Table created"));
        errors.add(PostgresHelper.executeUpdate("create table if not exists battle(usernamecreator text not null constraint battle_users_username_fk references users,usernameplayer text constraint battle_users_username_fk_2 references users, battleid serial, deckcreator text not null);"));
        errors.add(PostgresHelper.executeUpdateMessage("create unique index if not exists battle_battleid_uindex on battle (battleid);", "Battle Table created"));
        errors.add(PostgresHelper.executeUpdate("create table IF NOT EXISTS battle_log(id int not null constraint battle_log_pk primary key, playerone text not null,playertwo text not null,playeronescore text not null,playertwoscore text not null,log varchar(10485760));"));
        errors.add(PostgresHelper.executeUpdateMessage("create unique index IF NOT EXISTS battle_log_id_uindex on battle_log (id);", "Battle_lgo Table created"));
        return !errors.contains(false);
    }

    /**
     * Holt alle BattleIds an denen der User beteiligt war
     * @param username User der zu prüfen ist
     * @return Null bei fehler, sonst eine List aus den IDs
     */
    public ArrayList<String> getAllBattleIdUser(String username){
        this.c = PostgresHelper.con();
        int id;
        ArrayList<String> battleIds = new ArrayList<>();
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select id from battle_log where playerone = '" + username + "' or playertwo = '" + username + "';");
            while (rs.next()) {
                id = rs.getInt("id");
                if (id > 0) {
                    battleIds.add(id + "");
                }else {
                    return null;
                }
            }
            rs.close();
            stmt.close();
            this.c.close();
            return battleIds;
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
    }

    /**
     * Holt die Letzte BattleId eines users
     * @param username Userid die geprüft werden soll
     * @return -1 bei error, sonst die letzte battleid des users
     */
    public int getLastBattleIdUser(String username){
        this.c = PostgresHelper.con();
        int id;
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select max(id) from battle_log where playerone = '" + username + "' or playertwo = '" + username + "';");
            //noinspection LoopStatementThatDoesntLoop
            while (rs.next()) {
                id = rs.getInt("max");
                if (id > 0) {
                    return id;
                }else {
                    return -1;
                }
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return -1;
        }
        return -1;
    }

    /**
     * Holt das Battellog eines Bestimmten Battles
     * @param battleId Id des battles
     * @return Eine Map mit namen von player1 und player2, player1Score und player2Score und log
     */
    public Map<String, String> getBattleLog(String battleId){
        this.c = PostgresHelper.con();
        String playerone, playertwo, score1, score2, log;
        int id;
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select * from battle_log where id = " + battleId + ";");
            //noinspection LoopStatementThatDoesntLoop
            while (rs.next()) {
                id = rs.getInt("id");
                playerone = rs.getString("playerone");
                playertwo = rs.getString("playertwo");
                score1 = rs.getString("playeronescore");
                score2 = rs.getString("playertwoscore");
                log = rs.getString("log");
                if (id > 0 && !playerone.isEmpty() && !playertwo.isEmpty() && !score1.isEmpty() && !score2.isEmpty() && !log.isEmpty()){
                    Map<String, String> map = new java.util.HashMap<>(Collections.emptyMap());
                    map.put("playerone", playerone);
                    map.put("playertwo", playertwo);
                    map.put("playeronescore", score1);
                    map.put("playertwoscore", score2);
                    map.put("log", log);
                    map.put("id", id+"");
                    return map;
                }else{
                    return null;
                }

            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        return null;
    }


    /**
     * Fügt der Battle tabelle ein battle hinzu
     * @param usernamecreator Username der das Battle erstellt hat
     * @return True bei erfolg, sonst false
     */
    public boolean addBattle(String usernamecreator){
        ArrayList<String> decknamen = getDeck(usernamecreator);
        if(decknamen != null && !decknamen.isEmpty()){
            Cards deck = getCardsFromIDList(decknamen);
            if(deck != null && !deck.getCards().isEmpty()){
                String deckJson = JsonHelper.objToJson(deck.getCards());
                if (deckJson != null && !deckJson.isEmpty()){
                    return PostgresHelper.executeUpdateMessage("insert into battle (usernamecreator, deckcreator) VALUES ('" + usernamecreator + "','" + deckJson + "');", "Battle created");
                }else {
                    return false;
                }
            }else {
                return false;
            }
        }else{
            return false;
        }
    }

    /**
     * Sucht ein verfügbares open battle aus der DB und löscht gleichzeitig das open battle
     * @return Null falls keines verfügbar ist oder ein erir auftritt
     */
    public Battle getOpenBattle(){
        this.c = PostgresHelper.con();
        int battleid;
        String usernamecreator;
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select * from battle limit 1;");
            //noinspection LoopStatementThatDoesntLoop
            while (rs.next()) {
                battleid = rs.getInt("battleid");
                usernamecreator = rs.getString("usernamecreator");
                User player1 = new DBConnection().getUser(usernamecreator);
                if(player1 != null){
                    ArrayList<String> deckPlayer1Arr = new DBConnection().getDeck(usernamecreator);
                    if (deckPlayer1Arr != null){
                        Cards deckPlayer1 = new DBConnection().getCardsFromIDList(deckPlayer1Arr);
                        if(deckPlayer1 != null){
                            if(delBattleEinladung(battleid+"")){
                                return new Battle(battleid, player1, deckPlayer1);
                            }else{
                                return null;
                            }
                        }else{
                            return null;
                        }
                    }else {
                        return null;
                    }
                }else{
                    return null;
                }
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            return null;
        }
        return null;
    }

    /**
     * Löscht die Battle einladung eines einzelnen spielers
     * @param battleid Id die zu löschen ist
     * @return true bei erfolg sonst false
     */
    public boolean delBattleEinladung(String battleid){
        return PostgresHelper.executeUpdateMessage("delete from battle where battleid = '" + battleid + "';", "Battle req deleted");
    }


    /**
     * Nach einem Battle wird das log eingefügt, dabei wird die selbe id wie beim battle verwendet
     * @param id Id des Battles
     * @param playerone Name vom Player 1
     * @param playertwo Name vom Player 2
     * @param playeronescore Score vom Player 1
     * @param playertwoscore Score vom Player 2
     * @param log Log des Battles
     * @return true bei erfolg sonst false
     */
    public boolean addBattleLog(String id, String playerone, String playertwo, String playeronescore, String playertwoscore, String log){
        return PostgresHelper.executeUpdate("insert into battle_log (id, playerone, playertwo, playeronescore, playertwoscore, log) VALUES ("+id+ ",'" +playerone+ "','" +playertwo+ "','" +playeronescore+ "','" +playertwoscore+ "','" +log+ "');");
    }




    /**
     * Updated den Lock einer user card
     * @param name Name der Card
     * @param lock Zustand des Locks
     * @return true bei erfolg, sonst false
     */
    public boolean updateCardLock(String name, boolean lock){
        return PostgresHelper.executeUpdate("Update user_cards set gesperrt = " + lock + " where name = '" + name + "';");
    }


    /**
     * Prüft ob eine Card für das Deck gesperrt ist
     * @param name Name der Card die zu prüfen ist
     * @return True falls gesperrt, ansonst false
     * @throws SQLException Locked Cards konnten nicht aus der DB geholt werden
     */
    public boolean getCardLock(String name) throws SQLException {
        this.c = PostgresHelper.con();
        boolean locked = false;
        stmt = this.c.createStatement();
        ResultSet rs = stmt.executeQuery("select gesperrt from user_cards where name = '" + name + "';");
        while (rs.next()) {
            locked = rs.getBoolean("gesperrt");
        }
        rs.close();
        stmt.close();
        this.c.close();
        return locked;
    }

    /**
     * Löscht einen Trading Deal aus der Datenbank
     * @param id Id des deals der gelöscht werden soll
     * @return True bei erfolg, sonst false
     */
    public boolean deleteTradingDeal(String id){
        return PostgresHelper.executeUpdate("delete from trading where id = '" + id + "';");
    }

    /**
     * Fügt der DB einen Trading deal hinzu
     * @param username User der den Trade hinzufügt
     * @param id Id des Trades
     * @param mindamage Min damage der für den trade benötigt wird
     * @param reqcardtype Req Card Type der für den trade benötigt wird
     * @param reqelement Req Element Typ der für den trade benötigt wird
     * @param cardtotrade Card die zum Traden ist
     * @return True bei erfolg, sonst false
     */
    public boolean addTradingdeal(String username, String id, double mindamage, String reqcardtype, String reqelement, String cardtotrade){
        return PostgresHelper.executeUpdate("INSERT INTO public.trading (username, id, cardtotrade, mindamage, reqcardtype, reqelement) VALUES ('" + username + "','" + id + "','" + cardtotrade + "','" + mindamage + "','" + reqcardtype + "','" + reqelement + "');");
    }

    /**
     * Holt alle Trading Deals aus der DB
     * @return Null bei error
     */
    public ArrayList<TradingDeal> getAllTradingDeals(){
        this.c = PostgresHelper.con();
        ArrayList<TradingDeal> tradingDeals = new ArrayList<>();
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select * from trading;");
            while (rs.next()) {
                String username, id, cardtotrade, reqcardtype, reqelement;
                int mindamage;
                username = rs.getString("username");
                id = rs.getString("id");
                cardtotrade = rs.getString("cardtotrade");
                reqcardtype = rs.getString("reqcardtype");
                reqelement = rs.getString("reqelement");
                mindamage = rs.getInt("mindamage");

                Card card = new DBConnection().getCardFromID(cardtotrade);
                if(card != null){
                    TradingDeal tmp = new TradingDeal(id, card, mindamage, reqcardtype +reqelement, username);
                    tradingDeals.add(tmp);
                }else{
                    return null;
                }


            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        return tradingDeals;
    }

    /**
     * Setzt das Deck eines Users
     * @param username Username von dem das Deck gesetzt werden soll
     * @param deck Die ID´s des Decks in der Form einer ArrayList
     * @return True bei erfolg, sonst false
     */
    public boolean setDeck(String username, List<String> deck){
        for (String st :deck) {
            try {
                if(getCardLock(st)){
                    return false;
                }
            } catch (SQLException throwables) {
                System.err.println(throwables.getMessage());
                return false;
            }
        }
        Cards allCards = getCards(username);
        Cards deckCards = new Cards(new ArrayList<>());
        int count = 0;
        if(allCards != null && deck.size() == 4){
            for (String st : deck) {
                for (Card ca: allCards.getCards()) {
                    if(ca.getName().equals(st) && count < 4){
                        if(deckCards.getCards().size() == 0){
                            if (!delDeck(username)){
                                return false;
                            }
                        }
                        deckCards.addCard(ca);
                        if(deckCards.getCards().size() == 4){
                            int c = 0;
                            for(Card cardtmp : deckCards.getCards()){
                                c++;
                                if(!PostgresHelper.executeUpdateMessage("INSERT INTO public.user_deck (username, cardname) VALUES ('" +username+ "', '" +cardtmp.getName()+ "');", "Card #"+c+" added to Deck")){
                                    return false;
                                }
                            }
                            return true;
                        }
                    }
                }
                count++;
            }
            return false;
        }
        return false;
    }

    /**
     * Holt alle Card namen aus dem Deck eines Users
     * @param username user von dem die Deck namen geholt werden soll
     * @return null bedeuted error
     */
    public ArrayList<String> getDeck(String username){
        this.c = PostgresHelper.con();
        String cardname;
        ArrayList<String> cardnamenarray = new ArrayList<>();
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select * from user_deck where username = '" + username + "';");
            while (rs.next()) {
                cardname = rs.getString("cardname");
                cardnamenarray.add(cardname);
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        return cardnamenarray;
    }

    /**
     * Löscht den gesammten inhalt des Decks eines users
     * @param username Username von dem das Deck gelöscht werden soll
     * @return True bei erfolg, sonst false
     */
    public boolean delDeck(String username){
        return PostgresHelper.executeUpdateMessage("delete from user_deck where username = '" + username + "';", "User Deck: " + username + ", deleted");
    }


    /**
     * Holt ein Random package aus dem Shop
     *
     * @param username User der das Package haben möchte
     * @return Das Package aus dem Shop, null falls ein Fehler auftritt
     */
    public Package userAcquirePackage(String username) {
        this.c = PostgresHelper.con();
        String id = "";
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select \"ID\" as id from package LIMIT 1;");
            while (rs.next()) {
                id = rs.getString("id");
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        this.c = PostgresHelper.con();
        String packagename = "", cardname, elementtyp, cardtype;
        int damage;
        Cards cards = new Cards(new ArrayList<>());
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select  i as zeilennummer,  package.\"ID\" as id, package.name as packagename, c.name as cardname, c.DAMAGE as damage, c.ELEMENTTYP as elementtyp, c.CARDTYPE as cardtype from package join card c on c.name = package.name where \"ID\" = '" + id + "';");
            while (rs.next()) {
                id = rs.getString("id");
                packagename = rs.getString("packagename");
                cardname = rs.getString("cardname");
                elementtyp = rs.getString("elementtyp");
                cardtype = rs.getString("cardtype");
                damage = rs.getInt("damage");
                Card newCard = new Card(cardname, elementtyp + cardtype, damage);
                cards.addCard(newCard);
                if(!addUserCard(username, newCard.getName())){
                    return null;
                }
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        if(!deletePackage(id)){
            return null;
        }

        if (cards.getCards().size() != 0) {
            return new at.reisinger.obj.Package(cards, packagename, 5);
        } else {
            return null;
        }
    }

    /**
     * Löscht eine user card aus der DB
     * @param username Card löschen von
     * @param cardname Card die vom user zu löschen ist
     * @return True bei erfolg, sonst false
     */
    public boolean delUserCard(String username, String cardname){
        return PostgresHelper.executeUpdate("delete from user_cards where username = '" +username+ "' and name = '" +cardname+ "';");
    }

    /**
     * Fügt eine Card zu den User_Cards hinzu
     * @param username Username der die Card bekommt
     * @param cardName Card die der User bekommt
     * @return True bei erfolg, sonst false
     */
    public boolean addUserCard(String username, String cardName){
        Connection b = PostgresHelper.con();
        try {
            stmt = b.createStatement();
            String sql = "INSERT INTO public.user_cards (username, name, gesperrt) VALUES ( '" + username + "','" + cardName + "', 'false');";
            stmt.executeUpdate(sql);
            stmt.close();
            b.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return false;
        }
        return true;
    }
    /**
     * Löscht ein Package anhand des Namens
     *
     * @param name Name des Packages das gelöscht werden soll
     * @return True bei erfolg, sonst false
     */
    public boolean deletePackage(String name) {
        return PostgresHelper.executeUpdateMessage("DELETE FROM package WHERE \"ID\" = '" + name + "';", "Package deleted successfully");
    }


    /**
     * Coins setzten
     *
     * @param coins Anzahl die zu setzten ist
     * @param username Username von dem die Coins geupdated werden sollen
     * @return True bei erfolg, sonst false
     */
    public boolean updateCoins(int coins, String username) {
        return PostgresHelper.executeUpdateMessage("UPDATE users SET coins = " + coins + " WHERE username = '" + username + "';", "Coins Updated");
    }

    /**
     * Gibt die Anzahl an verfügbaren coins zurück
     * @param username Der username von dem die Coins geholt werden sollen
     * @return Anzahl der Coins, -1 ist error
     */
    public int checkCoins(String username) {
        this.c = PostgresHelper.con();
        int coins = 0;
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("Select coins from users where username = '" + username + "';");
            while (rs.next()) {
                coins = rs.getInt("coins");
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return -1;
        }
        return coins;
    }

    /**
     * Überprüft anhand des Namen der Karte, ob es schon eine solche Karte gibt
     *
     * @param name Name der zu prüfen ist
     * @return True falls die Karte bereits existiert
     */
    public boolean cardExists(String name) {
        this.c = PostgresHelper.con();
        int count = 0;
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select count(*) from card where name = '" + name + "';");
            while (rs.next()) {
                count = rs.getInt("count");
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            System.exit(0);
        }
        return count == 1;
    }

    /**
     * Fügt eine Karte der DB hinzu
     *
     * @param card Card die hinzugefügt werden soll
     * @return true bei erfolg, false bei error
     */
    public boolean addCard(Card card) {
        return PostgresHelper.executeUpdateMessage("insert into card (NAME, DAMAGE, ELEMENTTYP, CARDTYPE) values ('" + card.getName() + "','" + card.getDamage() + "','" + card.getElementTyp().name() + "','" + card.getCardType().name() + "')", "Card added");
    }

    /**
     * Ermittelt die nächste Package ID
     *
     * @return Die Nächste Package id, wenn 0, dann ist ein error
     */
    public int nextPackageId() {
        this.c = PostgresHelper.con();
        String id = "";
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select max(\"ID\") from package;");
            while (rs.next()) {
                id = rs.getString("max");
            }
            if (id == null) {
                id = "0";
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return 0;
        }
        return Integer.parseInt(id) + 1;
    }

    /**
     * Fügt eine Package der DB hinzu,
     * wenn eine Karte aus dem Package noch nicht in der Db ist,
     * dann wird es automatisch hinzugefuegt
     *
     * @param pack Pack welches hinzugefügt werden soll
     * @return True bei erfolg, false bei fehler
     */
    public boolean addPackage(at.reisinger.obj.Package pack) {
        for (Card ca : pack.getCards()) {
            if (!cardExists(ca.getName())) {
                if (!addCard(ca)) {
                    return false;
                }
            }
            if(!PostgresHelper.executeUpdateMessage("INSERT INTO package (\"ID\", \"name\") values ('" + pack.getName() + "','" + ca.getName() + "');", "Card zu Package hinzugefügt")){
                return false;
            }
        }
        return true;
    }

    /**
     * Fügt einen User der DB hinzu
     *
     * @param username Username des Users
     * @param password Passwort des Users
     * @param nachname nachname des Users
     * @param email    Email des Users
     * @param bio Bio des Users
     * @param image Image des Users
     * @return True wenn alles erfolgreich war, false wenn es nicht erfolgreich war
     */
    public boolean addUser(String username, String password, String nachname, String email, String bio, String image) {
        return PostgresHelper.executeUpdateMessage("INSERT INTO users (username, nachname, email, password, bio, image) values ('" + username + "','" + nachname + "','" + email + "','" + password + "','" + bio + "','" + image + "')", "User added");
    }

    /**
     * Updated den Nachnamen, Bio und das Image eines Users mit gegebenen usernamen
     * @param username User der geändert werden soll
     * @param bio Neue BIO
     * @param image Neues Image
     * @param name Neuer Nachname
     * @return True bei erfolg, sonst false
     */
    public boolean updateUser(String username, String bio, String image, String name){
        return PostgresHelper.executeUpdate("UPDATE public.users SET nachname = '" + name+ "', bio = '" +bio+ "', image = '" +image+ "' WHERE username LIKE '" +username+ "' ESCAPE '#'");
    }

    /**
     * Sucht einen User anhand des Usernamens.
     * Gibt ein User Objekt zurück
     *
     * @param uname Username der zu suchen ist
     * @return User als User Objekt, null bei fehler
     */
    public User getUser(String uname){
        this.c = PostgresHelper.con();
        String username = "", password = "", email = "", bio="", image="";
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM users where username = '" + uname + "';");
            while (rs.next()) {
                username = rs.getString("username");
                email = rs.getString("email");
                password = rs.getString("password");
                bio = rs.getString("bio");
                image = rs.getString("image");
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        return new User(new Credentials(username, password), username, username, email, new Coins(20), bio, image);
    }

    /**
     * Holt eine Card aus der DB, anhand der gegebenen Card Id
     * @param id Id der Card die geholt werden soll
     * @return Null bei error
     */
    public Card getCardFromID(String id){
        Connection b = PostgresHelper.con();
        Card toreturn = null;
        try {
            stmt = b.createStatement();
            ResultSet rs = stmt.executeQuery("select * from card where NAME =  '" + id + "';");
            while (rs.next()) {
                int damage =rs.getInt("damage");
                String elementtyp =rs.getString("elementtyp");
                String cardtype=rs.getString("cardtype");
                toreturn = new Card(id, elementtyp+cardtype, damage);
            }
            rs.close();
            stmt.close();
            b.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        return toreturn;
    }

    /**
     * Holt alle Carten einer gegebenen Card ID List
     * @param cardnamenarray Card IDs in einer Liste
     * @return Falls null, dann war ein error
     */
    public Cards getCardsFromIDList(List<String> cardnamenarray){
        Cards allCards = new Cards(new ArrayList<>());
        for (String st : cardnamenarray) {
            Connection b = PostgresHelper.con();
            try {
                stmt = b.createStatement();
                ResultSet rs = stmt.executeQuery("select * from card where NAME =  '" + st + "';");
                while (rs.next()) {
                    int damage =rs.getInt("damage");
                    String elementtyp =rs.getString("elementtyp");
                    String cardtype=rs.getString("cardtype");
                    allCards.addCard(new Card(st, elementtyp+cardtype, damage));
                }
                rs.close();
                stmt.close();
                b.close();
            } catch (Exception e) {
                System.err.println(e.getClass().getName() + ": " + e.getMessage());
                return null;
            }
        }
        return allCards;
    }

    /**
     * Holt alle Karten eines Users
     * @param username Username des Users
     * @return Cards Object, falls es null ist, war ein fehler
     */
    public Cards getCards(String username){
        this.c = PostgresHelper.con();
        String cardname;
        ArrayList<String> cardnamenarray = new ArrayList<>();
        try {
            stmt = this.c.createStatement();
            ResultSet rs = stmt.executeQuery("select * from user_cards where username = '" + username + "';");
            while (rs.next()) {
                cardname = rs.getString("name");
                cardnamenarray.add(cardname);
            }
            rs.close();
            stmt.close();
            this.c.close();
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            return null;
        }
        return getCardsFromIDList(cardnamenarray);
    }
}
