package dev.peerat.backend.routes.admins;

import java.util.function.BiConsumer;
import java.util.regex.Matcher;

import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseAdminRepository;
import dev.peerat.backend.repository.DatabasePlayerRepository;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key;
import dev.peerat.framework.Route;
import dev.peerat.framework.Router;
import dev.peerat.framework.utils.json.JsonArray;
import dev.peerat.framework.utils.json.JsonMap;

public class LogController {
	
	private Locker<Context> contextLocker;
	private Locker<Throwable> exceptionLocker;
	private DatabaseAdminRepository repo;
	private DatabasePlayerRepository playerRepo;
	
	public LogController(Router<PeerAtUser> router, DatabaseRepository repo){
		this.contextLocker = router.getLogger();
		this.exceptionLocker = router.getExceptionLogger();
		this.repo = repo.getAdminRepository();
		this.playerRepo = repo.getPlayerRepository();
	}
	
	@RouteDoc(path = "/admin/logs", responseCode = 200, responseDescription = "L'utilisateur peux voir les logs en directe")
	@RouteDoc(responseCode = 401, responseDescription = "L'utilisateur n'a pas accès à cette ressource")

	@Route(path = "^/admin/logs$", needLogin = true, websocket = true)
	public void logs(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
		log(reader, writer, this.contextLocker, (json, instance) -> {
			json.set("logged", instance.isLogged());
			if(instance.isLogged()) json.set("pseudo", playerRepo.getPlayer(instance.<PeerAtUser>getUser().getId()).getPseudo());
			json.set("path", instance.getPath());
			json.set("type", instance.getType().toString());
			json.set("code", instance.getResponseCode());
		});
	}
	
	@Route(path = "^/admin/exceptions$", needLogin = true, websocket = true)
	public void exceptions(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
		log(reader, writer, this.exceptionLocker, (json, exception) -> {
			json.set("type", exception.getClass().getSimpleName());
			json.set("message", exception.getMessage());
			JsonArray trace = new JsonArray();
			for(StackTraceElement element : exception.getStackTrace()) trace.add(element.toString());
			json.set("trace", trace);
		});
	}
	
	public <T> void log(HttpReader reader, HttpWriter writer, Locker<T> locker, BiConsumer<JsonMap, T> consumer){
		Key key = new Key();
		
		locker.init(key);
		try {
			while(!reader.isClosed()){
				locker.lock(key);
				T instance  = locker.getValue(key);
				JsonMap json = new JsonMap();
				consumer.accept(json, instance);
				
				writer.write(json.toString());
				writer.flush();
			}
		}catch(Exception e){}
		locker.remove(key);
	}

}
