package dev.peerat.backend.repository;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Badge;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.Player;
import dev.peerat.backend.model.Puzzle;

public class BaseDatabaseQuery{
	
	private ConnectionManager con;
	private Configuration config;
	
	public BaseDatabaseQuery(ConnectionManager con){
		this.con = con;
	}
	
	public Connection ensureConnection() throws SQLException{
		return this.con.ensureConnection();
	}
	
	public PreparedStatement prepare(String request) throws SQLException{
		return this.con.ensureConnection().prepareStatement(request);
	}
	
	public Puzzle makePuzzle(ResultSet puzzleResult) throws SQLException {
		return new Puzzle(puzzleResult.getInt("id_puzzle"), puzzleResult.getString("name"),
				puzzleResult.getString("content"), puzzleResult.getBytes("soluce"), puzzleResult.getString("verify"),
				puzzleResult.getInt("score_max"), puzzleResult.getString("tags"),
				hasColumn(puzzleResult, "origin") ? puzzleResult.getInt("origin") : -1,
				puzzleResult.getTimestamp("start_date"));
	}
	
	public Chapter makeChapter(ResultSet chapterResult) throws SQLException {
		return new Chapter(chapterResult.getInt("id_chapter"), chapterResult.getString("name"),
				chapterResult.getTimestamp("start_date"), chapterResult.getTimestamp("end_date"));
	}

	public Completion makeCompletion(ResultSet completionResult) throws SQLException {
		String fileName = null;
		if (hasColumn(completionResult, "fileName"))
			fileName = completionResult.getString("fileName");
		String puzzleName = null;
		if (hasColumn(completionResult, "name"))
			puzzleName = completionResult.getString("name");
		
		return new Completion(completionResult.getInt("fk_player"), completionResult.getInt("fk_puzzle"), completionResult.getInt("tries"),
				fileName, completionResult.getInt("score"), puzzleName);
	}

	public Player makePlayer(ResultSet playerResult, int id) throws SQLException {
		Player p = new Player(playerResult.getString("pseudo"), playerResult.getString("email"),
				playerResult.getString("firstName"), playerResult.getString("lastName"));
		if (hasColumn(playerResult, "avatar")) {
			p.setAvatar(playerResult.getBytes("avatar"));
		}
		if (hasColumn(playerResult, "score")) {
			p.addCompletion(new Completion(playerResult.getInt("tries"), playerResult.getInt("score")));
			for (int ct = 1; ct < playerResult.getInt("completions"); ct++)
			{	// TODO refactor for V3
				p.addCompletion(new Completion(0, 0));
			}
		}
		if (hasColumn(playerResult, "name")) {
			// Manage groups
			String groupName = playerResult.getString("name");
			if (groupName != null) {
				p.addGroup(makeGroup(playerResult));
			}
		}

		// ADD rank
		PreparedStatement completionsStmt = con.ensureConnection().prepareStatement(DatabasePlayerRepository.GET_PLAYER_RANK());
		completionsStmt.setInt(1, id);
		ResultSet result = completionsStmt.executeQuery();
		while (result.next()) {
			p.setRank(result.getInt("rank"));
		}
		return p;
	}

	public Group makeGroup(ResultSet result) throws SQLException {
		return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle"), ((hasColumn(result, "countPlayer")) ? result.getInt("countPlayer") : 0));
	}

	public Player makeGroupPlayer(ResultSet result) throws SQLException {
		return new Player(result.getString("pseudo"), result.getInt("score"), result.getInt("tries"));
	}

	public Badge makeBadge(ResultSet rs) throws SQLException {
		return new Badge(rs.getString("name"), rs.getBytes("logo"), rs.getInt("level"));
	}

	public boolean hasColumn(ResultSet rs, String columnName) throws SQLException {
		// Found on StackOverflow
		ResultSetMetaData rsmd = rs.getMetaData();
		int columns = rsmd.getColumnCount();
		for (int x = 1; x <= columns; x++) {
			if (columnName.equals(rsmd.getColumnName(x)))
				return true;
		}
		return false;
	}


}
