package dev.peerat.backend;

import static dev.peerat.framework.RequestType.OPTIONS;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;

import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.routes.BadgeDetails;
import dev.peerat.backend.routes.ChapterElement;
import dev.peerat.backend.routes.ChapterList;
import dev.peerat.backend.routes.DynamicLeaderboard;
import dev.peerat.backend.routes.Leaderboard;
import dev.peerat.backend.routes.PlayerDetails;
import dev.peerat.backend.routes.PuzzleElement;
import dev.peerat.backend.routes.PuzzleResponse;
import dev.peerat.backend.routes.Result;
import dev.peerat.backend.routes.admins.DynamicLogs;
import dev.peerat.backend.routes.groups.GroupCreate;
import dev.peerat.backend.routes.groups.GroupJoin;
import dev.peerat.backend.routes.groups.GroupList;
import dev.peerat.backend.routes.groups.GroupQuit;
import dev.peerat.backend.routes.users.ChangePassword;
import dev.peerat.backend.routes.users.ForgotPassword;
import dev.peerat.backend.routes.users.Login;
import dev.peerat.backend.routes.users.MailConfirmation;
import dev.peerat.backend.routes.users.ProfileSettings;
import dev.peerat.backend.routes.users.Register;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Locker;
import dev.peerat.framework.RequestType;
import dev.peerat.framework.Response;
import dev.peerat.framework.Route;
import dev.peerat.framework.Router;

public class Main{
	public static void main(String[] args) throws Exception{
		Configuration config = new Configuration("config.txt")
				.addDefaultValue("users_files", "/tmp/users_files");
		config.load();

		Class.forName("com.mysql.cj.jdbc.Driver");

		DatabaseRepository repo = new DatabaseRepository(config);
		Router<PeerAtUser> router = new Router<PeerAtUser>()
				.configureJwt(
						(builder) -> builder.setExpectedIssuer(config.getTokenIssuer()),
						(claims) -> {
							claims.setIssuer(config.getTokenIssuer()); // who creates the token and signs it
							claims.setExpirationTimeMinutesInTheFuture(config.getTokenExpiration());
						}, 
						(claims) -> new PeerAtUser(claims))
				.activeReOrdering().
				addDefaultHeaders(RequestType.GET, "Access-Control-Allow-Origin: *").
				addDefaultHeaders(RequestType.POST, "Access-Control-Allow-Origin: *").
				addDefaultHeaders(RequestType.OPTIONS,
						"Access-Control-Allow-Origin: *",
						"Access-Control-Allow-Methods: *",
						"Access-Control-Allow-Headers: *");

		router.setDefault((matcher, context, reader, writer) -> {
			context.response(404);
			writer.write("404 not Found.\n");
		});
		
		router.register(new Response(){
			@Route(path = "^(.*)$", type = OPTIONS)
			public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
				context.response(200);
			}

		});
		
		initRoutes(router, repo, config);

//		RouteExtracter extracter = new RouteExtracter(router);
//		extracter.extract();
		
		if(config.useSsl()) router.configureSSL(config.getSslKeystore(), config.getSslKeystorePasswd());
		router.listen(config.getTcpPort(), config.useSsl());
	}

	private static void initRoutes(Router<PeerAtUser> router, DatabaseRepository repo, Configuration config){
		Map<String, Integer> playersWaiting = new HashMap<>();
		router.register(new Register(repo, playersWaiting));
		router.register(new MailConfirmation(repo, router, config.getUsersFiles(), config.getGitToken(), playersWaiting));
		router.register(new Login(repo, router));
		router.register(new ProfileSettings(repo));
		router.register(new ChangePassword(repo));
		router.register(new ForgotPassword());
		
		router.register(new DynamicLogs(repo, router.getLogger()));
		
		router.register(new ChapterElement(repo));
		router.register(new ChapterList(repo));
		router.register(new PuzzleElement(repo));
		router.register(new Result(repo));
		router.register(new Leaderboard(repo));
		router.register(new PlayerDetails(repo));
		router.register(new BadgeDetails(repo));
		
		Locker<Group> groupLock = new Locker<>();
		Locker<Completion> leaderboard = new Locker<>();
		
		router.register(new DynamicLeaderboard(repo, leaderboard));
		router.register(new PuzzleResponse(repo, config.getUsersFiles(), leaderboard));
		
		router.register(new GroupCreate(repo, groupLock, config.getGroupJoinMinutes()));
		router.register(new GroupList(repo));
		router.register(new GroupJoin(repo, config.getGroupJoinMinutes(), config.getGroupQuitMinutes(), leaderboard));
		router.register(new GroupQuit(repo, config.getGroupJoinMinutes(), leaderboard));
		
//		Bot bot = new Bot(config, repo, groupLock);
//		bot.start();
	}
}
