package com.github.games647.flexiblelogin.storage;

import com.github.games647.flexiblelogin.config.Settings;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Optional;
import java.util.UUID;

import org.slf4j.Logger;
import org.spongepowered.api.entity.living.player.User;

public class AuthMeDatabase extends Database {

    public AuthMeDatabase(Logger logger, Settings settings) throws SQLException {
        super(logger, settings, settings.getGeneral().getSQL().getAuthMeTable());
    }

    @Override
    public Optional<Account> loadAccount(UUID uuid) {
        //AuthMe doesn't use UUIDs
        return Optional.empty();
    }

    @Override
    public boolean deleteAccount(UUID uuid) {
        //AuthMe doesn't use UUIDs
        return false;
    }

    @Override
    public Optional<Account> loadAccount(User player) {
        return loadAccount(player.getName());
    }

    @Override
    public Optional<String> exists(String username) {
        return exists(username, "realname");
    }

    @Override
    public Optional<Account> loadAccount(String playerName) {
        String sql = "SELECT realname, password, ip, lastlogin, email FROM " + tableName + " WHERE realname=?";
        return loadAccount(sql, stmt -> stmt.setString(1, playerName));
    }

    @Override
    public boolean deleteAccount(String playerName) {
        return deleteAccount("realname", stmt -> stmt.setString(1, playerName));
    }

    @Override
    public int getRegistrationsCount(InetAddress ip) {
        return getRegistrationsCount(ip, stmt -> stmt.setString(1, ip.getHostAddress()));
    }

    @Override
    public boolean createAccount(Account account) {
        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + tableName
                     + " (username, realname, password, ip, lastlogin, email) VALUES (?,?,?,?,?,?)")) {
            writeAccount(stmt, account);
            stmt.executeUpdate();

            return true;
        } catch (SQLException sqlEx) {
            logger.error("Error registering account", sqlEx);
        }

        return false;
    }

    @Override
    public boolean save(Account account) {
        try (Connection con = dataSource.getConnection();
             PreparedStatement stmt = con.prepareStatement("UPDATE " + tableName + " SET realname=?, realname=?, "
                     + "password=?, ip=?, lastlogin=?, email=?, isLogged=? WHERE realname=?")) {
            writeAccount(stmt, account);

            stmt.setBoolean(7, account.isLoggedIn());
            stmt.setString(8, account.getUsername());

            stmt.executeUpdate();
            return true;
        } catch (SQLException ex) {
            logger.error("Error saving user account", ex);
        }

        return false;
    }

    private void writeAccount(PreparedStatement stmt, Account account) throws SQLException {
        stmt.setString(1, account.getUsername().toLowerCase());
        stmt.setString(2, account.getUsername());
        stmt.setString(3, account.getPassword());
        stmt.setString(4, account.getIP().getHostAddress());

        stmt.setTimestamp(5, Timestamp.from(account.getLastLogin()));
        stmt.setString(6, account.getEmail().orElse(null));
    }

    @Override
    protected Optional<Account> parseLoadResult(ResultSet resultSet) throws SQLException {
        if (resultSet.next()) {
            String username = resultSet.getString(1);
            String password = resultSet.getString(2);

            InetAddress ip = parseAddress(resultSet.getString(3));
            Timestamp lastLogin = resultSet.getTimestamp(4);
            String email = resultSet.getString(5);

            UUID offlineUUID = Account.getOfflineUUID(username);
            return Optional.of(new Account(offlineUUID, username, password, ip, email, lastLogin.toInstant()));
        }

        return Optional.empty();
    }

    private InetAddress parseAddress(String hostName) {
        if (hostName == null || hostName.isEmpty()) {
            return null;
        }

        try {
            return InetAddress.getByName(hostName);
        } catch (UnknownHostException e) {
            return null;
        }
    }
}

@@ -1007,38 +1007,58 @@
 ayer) %7B%0A        
-return
+Optional%3CAccount%3E optAcc =
  loadAccount(pla
@@ -1069,24 +1069,126 @@
 getName());%0A
+        optAcc.ifPresent(account -%3E cache.put(player.getUniqueId(), account));%0A        return optAcc;%0A
     %7D%0A%0A    @

Load players to cache in AuthMe (Fixes #115)