package org.academiadecodigo.bootcamp.fxlogin.service.user;

import org.academiadecodigo.bootcamp.fxlogin.model.User;
import org.academiadecodigo.bootcamp.fxlogin.persistence.ConnectionManager;
import org.academiadecodigo.bootcamp.fxlogin.utils.Security;

import java.sql.*;

/**
 * MIT License
 * (c) 2017 Ricardo Constantino
 */

public class JdbcUserService implements UserService {

    private Connection dbConnection;
    private final String tableName = "users";

    public JdbcUserService() {

        dbConnection = ConnectionManager.getInstance().getConnection();

    }

    @Override
    public boolean authenticate(String username, String password) {

        reopenConnectionIfNeeded();

        try {
            String query = String.format("SELECT name, password FROM %s WHERE name = ?", tableName);
            PreparedStatement statement = dbConnection.prepareStatement(query);

            statement.setString(1, username);

            ResultSet resultSet = statement.executeQuery();


            String dbUsername = null;
            String dbPass = null;
            if (resultSet.next()) {
                dbUsername = resultSet.getString("name");
                dbPass = resultSet.getString("password");
            }

            statement.close();

            return dbUsername != null && dbPass != null &&
                    dbUsername.equals(username) && dbPass.equals(Security.getHashed(password));


        } catch (SQLException e) {
            e.printStackTrace();
        }

        return false;
    }

    @Override
    public void addUser(User user) {

        reopenConnectionIfNeeded();

        if (findByName(user.getUsername()) != null) {
            System.out.println("Tried to add already existing user.");
            return;
        }

        System.out.println("Adding new user.");
        try {
            String query = String.format("INSERT INTO %s (name, password, email) VALUES (?, ?, ?)",
                    tableName);
            PreparedStatement statement = dbConnection.prepareStatement(query);

            statement.setString(1, user.getUsername());
            statement.setString(2, user.getPassword());
            statement.setString(3, user.getEmail());

            if (!statement.execute()) {
                System.out.println("User adding failed.");
            }

            statement.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    @Override
    public User findByName(String username) {

        reopenConnectionIfNeeded();

        User user = null;

        try {
            String query = String.format("SELECT name, password, email FROM %s WHERE name = ?",
                    tableName);
            PreparedStatement statement = dbConnection.prepareStatement(query);

            statement.setString(1, username);

            ResultSet resultSet = statement.executeQuery();

            if (resultSet.next()) {
                String newUsername = resultSet.getString("name");
                String newPass = resultSet.getString("password");
                String newEmail = resultSet.getString("email");
                user = new User(newUsername, newPass, newEmail);
            }

            statement.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }

        return user;

    }

    @Override
    public Long count() {

        reopenConnectionIfNeeded();

        long result = 0;

        try {
            Statement statement = dbConnection.createStatement();

            String query = "SELECT COUNT(*) FROM " + tableName;

            ResultSet resultSet = statement.executeQuery(query);

            if (resultSet.next()) {
                result = resultSet.getLong(1);
            }

            statement.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }


        return result;
    }

    private void reopenConnectionIfNeeded() {
        try {
            if (dbConnection == null || dbConnection.isClosed()) {
                dbConnection = ConnectionManager.getInstance().getConnection();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
