package me.blackphreak.CommandHandling.Handlers;

import me.blackphreak.CommandHandling.AbstractCommandHandler;
import me.blackphreak.Database;
import me.blackphreak.Debug.Debug;
import me.blackphreak.Student.AbstractStudent;
import me.blackphreak.Student.Types.LocalStudent;
import me.blackphreak.Student.Types.OverseaStudent;

import static me.blackphreak.Lib.promptQuestion;

public class CreateStudentCommand extends AbstractCommandHandler {
	public CreateStudentCommand(String desc) {
		super(desc);
	}
	
	@Override
	public boolean handle() {
		AbstractStudent stu = null;
		
		do {
			var inp = promptQuestion("Enter type of the student [local | oversea]: ");
			
			if (inp.equalsIgnoreCase("local")) {
				stu = new LocalStudent();
			}
			else if (inp.equalsIgnoreCase("oversea")) {
				stu = new OverseaStudent();
			}
			else {
				System.out.println("Invalid type. Please try again.");
			}
		} while (stu == null);
		
		System.out.println("  Please provide information about the student:");
		// prompt special question first
		stu.promptQuestionEx();
		
		do {
			var inp = promptQuestion("    Chinese Name (allow empty): ", false);
			
			if (stu instanceof LocalStudent)
			{
				if (inp.isEmpty() || inp.isBlank())
					System.out.println("Invalid. Please try again.");
				else
					stu.setChtName(inp);
			}
			else if (stu instanceof OverseaStudent)
				stu.setChtName("");
			
		} while (stu.getChtName() == null);
		
		do {
			var inp = promptQuestion("    English Name: ", false);
			
			if (inp.isEmpty() || inp.isBlank())
				System.out.println("Invalid. Please try again.");
			else
				stu.setEngName(inp);
		} while (stu.getEngName() == null);
		
		do {
			var inp = promptQuestion("    Home Address: ", false);
			
			if (inp.isEmpty() || inp.isBlank())
				System.out.println("Invalid. Please try again.");
			else
				stu.setHomeAddress(inp);
		} while (stu.getHomeAddress() == null);
		
		do {
			var inp = promptQuestion("    Mobile Number: ", false);
			
			if (inp.isEmpty()
					|| inp.isBlank()
					|| !inp.matches("\\d+"))
				System.out.println("Invalid. Please try again.");
			else
				stu.setMobileNumber(inp);
		} while (stu.getMobileNumber() == null);
		
		do {
			var inp = promptQuestion("    Nationality: ", false)
					.toUpperCase();
			
			if (inp.isEmpty()
					|| inp.isBlank())
				System.out.println("Invalid nationality. Please try again.");
			else
				stu.setNationality(inp);
		} while (stu.getNationality() == null);
		
		do {
			var inp = promptQuestion("    Current Semester: ", false);
			
			if (inp.isEmpty()
					|| inp.isBlank()
					|| !inp.matches("\\d{1,1}"))
				System.out.println("Invalid. Please try again.");
			else
				stu.setSemester(Integer.parseInt(inp));
		} while (stu.getSemester() <= 0);
		
		String tryAgain;
		do {
			if (!stu.allocateStudentID()) {
				Debug.err("Failed to allocate studentID!");
				do {
					tryAgain = promptQuestion(
							"** n: will discard all unsaved changes! **\n" +
									"Try to allocate again? [Y/n]: "
					);
					
					// check for tryAgain option
					// if not empty (not using the default answer)
					// AND not a valid option (not either Y nor n)
					//      prompt the question again
				} while (!tryAgain.isEmpty() && (
						!tryAgain.equalsIgnoreCase("Y")
								|| !tryAgain.equalsIgnoreCase("n")
				));
			}
			else
				break;
		} while (tryAgain.isEmpty() || tryAgain.equalsIgnoreCase("Y"));
		
		if (stu.getStudentID().isEmpty()) {
			Debug.err("Failed to allocate studentID. Back to main menu.");
			return true;
		}
		
		Debug.info("Student["+stu.getStudentID()+"] created. Saving to database...");
		
		// save to db (those SQL injection attack, I don't give a f___ in this project)
		var sb = new StringBuilder("INSERT INTO Student (StudentID, ChtName, EngName, Address, MobileNum, Nationality, ");
		String sql;
		
		if (stu instanceof LocalStudent) {
			var tmpStu = (LocalStudent)stu;
			
			//StudentID, ChtName, EngName, Address, MobileNum, Nationality, HKID
			sb.append("HKID) VALUES (\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\");");
			
			sql = String.format(
					sb.toString(),
					tmpStu.getStudentID(),
					tmpStu.getChtName(),
					tmpStu.getEngName(),
					tmpStu.getHomeAddress(),
					tmpStu.getMobileNumber(),
					tmpStu.getNationality(),
					tmpStu.getHKID()
			);
		}
		else if (stu instanceof OverseaStudent) {
			var tmpStu = (OverseaStudent)stu;
			
			//StudentID, ChtName, EngName, Address, MobileNum, Nationality, VISA
			sb.append("VISA) VALUES (\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\");");
			
			sql = String.format(
					sb.toString(),
					tmpStu.getStudentID(),
					tmpStu.getChtName() == null || tmpStu.getChtName().isEmpty()
							? null
							: tmpStu.getChtName(),
					tmpStu.getEngName(),
					tmpStu.getHomeAddress(),
					tmpStu.getMobileNumber(),
					tmpStu.getNationality(),
					tmpStu.getVisa()
			);
		}
		else
		{
			Debug.err("Unknown student type.");
			return true;
		}
		
		// obj to json
		System.out.println("** Lazy creation: "+stu.toJson()+" **");
		
		Database.getInstance().update(sql);
		
		Debug.info("Success. Returning to main menu.");
		return true;
	}
}
