package dev.peerat.backend.repository;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;

public class DatabaseGroupRepository extends BaseDatabaseQuery{
	
	private static enum Query{
		
		// GROUPS
		ALL_GROUPS("SELECT * FROM groups"),
		ALL_GROUPS_BY_CHAPTER("select g.*, count(cg.fk_player) as countPlayer from groups g left join containsGroups cg on cg.fk_group = g.id_group where g.fk_chapter = ? group by g.id_group"),
		GET_GROUP_FOR_PLAYER("SELECT g.* FROM groups g JOIN containsGroups cg ON cg.fk_group = g.id_group WHERE cg.fk_player = ? AND g.fk_chapter = ?"), // AND g.fk_puzzle = ?
		GET_GROUP_ID_BY_DATA("SELECT id_group FROM groups WHERE name = ? AND (fk_chapter = ?)"), // OR fk_puzzle = ?
		GET_GROUP_USERS_COUNT("SELECT count(*) as howmany FROM containsGroups WHERE fk_group = ?"),
		INSERT_GROUP("INSERT INTO groups (name, fk_chapter) VALUES (?,?)"),
		INSERT_PLAYER_IN_GROUP("INSERT INTO containsGroups (fk_player, fk_group) VALUES (?,?)"),
		LEAVE_GROUP("DELETE FROM containsGroups WHERE fk_player = ? AND fk_group = ?");

		private String request;

		Query(Query parent, String request) {
			this.request = parent.request + request;
		}

		Query(String request) {
			this.request = request;
		}

		public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
			return base.prepare(this.request);
		}

		@Override
		public String toString() {
			return this.request;
		}
	}
	
	private Configuration config;
	
	public DatabaseGroupRepository(ConnectionManager con, Configuration config){
		super(con);
		this.config = config;
	}
	
	public List<Group> getAllGroups() {
		try {
			ensureConnection();
			List<Group> list = new ArrayList<>();
			PreparedStatement stmt = Query.ALL_GROUPS.prepare(this);
			ResultSet groupResult = stmt.executeQuery();
			while (groupResult.next())
				list.add(makeGroup(groupResult));
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public List<Group> getAllGroupsByChapter(int chapter){
		try {
			ensureConnection();
			List<Group> list = new ArrayList<>();
			PreparedStatement stmt = Query.ALL_GROUPS_BY_CHAPTER.prepare(this);
			stmt.setInt(1, chapter);
			ResultSet groupResult = stmt.executeQuery();
			while (groupResult.next())
				list.add(makeGroup(groupResult));
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public boolean insertGroup(Group group, PeerAtUser creator) throws SQLException {
		Integer groupId = getGroupId(group);
		if (groupId == null)
			ensureConnection();
			PreparedStatement statement = Query.INSERT_GROUP.prepare(this);
			statement.setString(1, group.getName());
			statement.setObject(2, group.getLinkToChapter());
//			statement.setObject(3, group.getLinkToPuzzle());
			if (statement.executeUpdate() >= 0)
				return insertUserInGroup(group, creator);
		return false;
	}

	public Group getPlayerGroup(int user, Integer chapter) throws SQLException {
		ensureConnection();
		PreparedStatement stmt = Query.GET_GROUP_FOR_PLAYER.prepare(this);
		stmt.setInt(1, user);
		stmt.setObject(2, chapter);
//		stmt.setObject(3, puzzle);

		ResultSet result = stmt.executeQuery();
		if (result.next())
			return makeGroup(result);
		return null;
	}

	public Integer getGroupId(Group group) throws SQLException {
		ensureConnection();
		PreparedStatement stmt = Query.GET_GROUP_ID_BY_DATA.prepare(this);
		stmt.setString(1, group.getName());
		stmt.setObject(2, group.getLinkToChapter());
//		stmt.setObject(3, group.getLinkToPuzzle());

		ResultSet result = stmt.executeQuery();
		if (result.next())
			return result.getInt("id_group");
		return null;
	}

	public boolean insertUserInGroup(Group group, PeerAtUser user) throws SQLException{
		Integer id = getGroupId(group);
		if(id != null){
			int howmany = numberInGroup(id);
			System.out.println("join group, already have "+howmany);
			if(howmany > config.getGroupMaxPlayers()) return false;
		}
		Group alreadyInGroup = getPlayerGroup(user.getId(), group.getLinkToChapter());
		if (id != null && alreadyInGroup == null) {
			PreparedStatement stmt = Query.INSERT_PLAYER_IN_GROUP.prepare(this);

			stmt.setInt(1, user.getId());
			stmt.setInt(2, id);

			return stmt.executeUpdate() >= 0;
		}
		return false;
	}
	
	public int numberInGroup(int group) throws SQLException{
		PreparedStatement stmt = Query.GET_GROUP_USERS_COUNT.prepare(this);
		stmt.setInt(1, group);

		ResultSet result = stmt.executeQuery();
		if(result.next()) return result.getInt("howmany");
		return 0;
	}

	public boolean leaveGroup(Group group, PeerAtUser user) throws SQLException {
		Integer id = getGroupId(group);
		if (id != null) {
			PreparedStatement stmt = Query.LEAVE_GROUP.prepare(this);

			stmt.setInt(1, user.getId());
			stmt.setInt(2, id);

			return stmt.executeUpdate() >= 0;
		}
		return false;
	}

}
