package dev.peerat.backend.repository;

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.Chapter;
import dev.peerat.backend.model.Puzzle;
import dev.peerat.backend.model.Tag;

public class DatabaseAdminRepository extends BaseDatabaseQuery{
	
	private static enum Query{
		
		//ADMIN
		ADD_CHAPTER("INSERT INTO chapters (name, start_date, end_date) VALUES (?,?,?)"),
		DELETE_CHAPTER("DELETE FROM chapters WHERE id_chapter = ?"),
		EDIT_CHAPTER("UPDATE chapters SET name = ?, start_date = ?, end_date = ? WHERE id_chapter = ?"),
		GET_CHAPTER("SELECT * FROM chapters WHERE id_chapter = ?"),
		
		ADD_PUZZLE("INSERT INTO puzzles (name, content, soluce, verify, score_max, fk_chapter) VALUES (?,?,?,?,?,?)"),
		DELETE_PUZZLE("DELETE FROM puzzles WHERE id_puzzle = ?"),
		EDIT_PUZZLE("UPDATE puzzles SET name = ?, content = ?, soluce = ?, verify = ?, score_max = ?, fk_chapter = ? WHERE id_puzzle = ?"),
		GET_PUZZLE("SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE p.id_puzzle = ? GROUP BY p.id_puzzle"),
		GET_PUZZLES("SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag GROUP BY p.id_puzzle"),
		
		ADD_TAG("INSERT INTO tags (name) VALUES (?)"),
		DELETE_TAG("DELETE FROM tags WHERE id_tag = ?"),
		EDIT_TAG("UPDATE tags SET name = ? WHERE id_tag = ?"),
		GET_TAGS("SELECT * FROM tags");

		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 DatabaseAdminRepository(ConnectionManager con, Configuration config){
		super(con);
		this.config = config;
	}
	
	//ADMIN
		public Chapter getAdminChapter(int id){
			try {
				PreparedStatement chapterStmt = Query.GET_CHAPTER.prepare(this);
				chapterStmt.setInt(1, id);
				ResultSet chapterResult = chapterStmt.executeQuery();
				if (chapterResult.next()) {
					Chapter chapter = makeChapter(chapterResult);
					return chapter;
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		public Puzzle getAdminPuzzle(int id){
			try {
				PreparedStatement chapterStmt = Query.GET_PUZZLE.prepare(this);
				chapterStmt.setInt(1, id);
				ResultSet chapterResult = chapterStmt.executeQuery();
				if (chapterResult.next()) {
					return makePuzzle(chapterResult);
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		public List<Puzzle> getAdminPuzzles(){
			try {
				PreparedStatement chapterStmt = Query.GET_PUZZLES.prepare(this);
				ResultSet chapterResult = chapterStmt.executeQuery();
				List<Puzzle> list = new ArrayList<>();
				while(chapterResult.next()){
					list.add(makePuzzle(chapterResult));
				}
				return list;
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		public List<Tag> getAdminTags(){
			try {
				PreparedStatement chapterStmt = Query.GET_TAGS.prepare(this);
				ResultSet chapterResult = chapterStmt.executeQuery();
				List<Tag> list = new ArrayList<>();
				while(chapterResult.next()){
					list.add(new Tag(chapterResult.getInt("id_tag"), chapterResult.getString("name")));
				}
				return list;
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		public boolean adminAddChapter(Chapter chapter) throws SQLException {
			PreparedStatement statement = Query.ADD_CHAPTER.prepare(this);
			statement.setString(1, chapter.getName());
			statement.setTimestamp(2, chapter.getStartDate());
			statement.setTimestamp(3, chapter.getEndDate());
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminAddPuzzle(Puzzle puzzle, int chapter) throws SQLException {
			PreparedStatement statement = Query.ADD_PUZZLE.prepare(this);
			statement.setString(1, puzzle.getName());
			statement.setString(2, puzzle.getContent());
			statement.setBytes(3, puzzle.getSoluce());
			statement.setString(4, "");
			statement.setInt(5, puzzle.getScoreMax());
			statement.setInt(6, chapter);
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminAddTag(String name) throws SQLException {
			PreparedStatement statement = Query.ADD_TAG.prepare(this);
			statement.setString(1, name);
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminUpdateChapter(int id, Chapter chapter) throws SQLException {
			PreparedStatement statement = Query.EDIT_CHAPTER.prepare(this);
			statement.setString(1, chapter.getName());
			statement.setTimestamp(2, chapter.getStartDate());
			statement.setTimestamp(3, chapter.getEndDate());
			statement.setInt(4, id);
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminUpdatePuzzle(int id, Puzzle puzzle, int chapter) throws SQLException {
			PreparedStatement statement = Query.EDIT_PUZZLE.prepare(this);
			statement.setString(1, puzzle.getName());
			statement.setString(2, puzzle.getContent());
			statement.setBytes(3, puzzle.getSoluce());
			statement.setString(4, "");
			statement.setInt(5, puzzle.getScoreMax());
			statement.setInt(6, chapter);
			statement.setInt(7, id);
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminUpdateTag(Tag tag) throws SQLException {
			PreparedStatement statement = Query.EDIT_TAG.prepare(this);
			statement.setString(1, tag.getName());
			statement.setInt(2, tag.getId());
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminDeleteChapter(int id) throws SQLException {
			PreparedStatement statement = Query.DELETE_CHAPTER.prepare(this);
			statement.setInt(1, id);
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminDeletePuzzle(int id) throws SQLException {
			PreparedStatement statement = Query.DELETE_PUZZLE.prepare(this);
			statement.setInt(1, id);
			return (statement.executeUpdate() >= 0);
		}
		
		public boolean adminDeleteTag(int id) throws SQLException {
			PreparedStatement statement = Query.DELETE_TAG.prepare(this);
			statement.setInt(1, id);
			return (statement.executeUpdate() >= 0);
		}

}
