import { Router, Request, Response, NextFunction } from "express";
import { InvalidParameterError } from "../errors/invalidParameterError";
import { titreBase } from "../utils/define";
import { coursController, questionControleur } from "../locator";
import { Cours } from "../classes/cours";
import { Question } from "../classes/question";
import { LoginControlleur } from "../controleurs/loginControleur";
import { COOKIE_TOKEN } from "../utils/constant";
import { Enseignant } from "../classes/enseignant";
import { Utilisateur } from "../models/utilisateur";
import { authenticate } from "../middlewares/authenticate";

export class QuestionRouter {
  private _router: Router;
  private _loginControleur: LoginControlleur;

  get router() {
    return this._router;
  }

  constructor() {
    this._router = Router();
    this.init();
  }

  private _errorCode500(
    error: any,
    req: Request,
    res: Response<any, Record<string, any>>
  ) {
    console.warn(`error500 - ${error.message}`);
    req.flash("error", error.message);
    res.status(error.code).json({ error: error.toString() });
  }

  public getControleur() {
    return questionControleur;
  }


  // IS THIS STILL NECESSARY??
  public async questionnaires(req: Request, res: Response, next: NextFunction) {
    const user = await this._loginControleur.getUtilisateur(
      req.cookies[COOKIE_TOKEN]
    );
    try {
      res.render("question/questionnaire", {
        title: `${titreBase}`,
        user: user,
      });
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  public async visualiserCoursActifs(
    req: Request,
    res: Response,
    next: NextFunction
  ) {
    try {
      const user = req.body.user as Enseignant;
      const code = req.params.code;

      let coursActifs:Cours[] = [];
      const coursRecuperes = coursController.recupererCours(user) as Cours[];
      
      coursRecuperes.forEach(cours => {
        if(cours.getEnseignantId() === user.id && cours.actif)
          coursActifs.push(cours);
      });

      res.render("question/cours-actifs", {
        title: `${titreBase}`,
        user: user,
        code: code,
        coursActifs: coursActifs
      });
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  public async formulerQuestion(
    req: Request,
    res: Response,
    next: NextFunction
  ) {
    try {
      const user = req.body.user as Enseignant;
      const code = req.params.code;
      res.render("question/formuler-question", {
        title: `${titreBase}`,
        user: user,
        code: code,
      });
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  public async reformulerQuestion(
    req: Request,
    res: Response,
    next: NextFunction
  ) {
    try {
      const user = req.body.user as Enseignant;
      const question: Question = questionControleur.recupererQuestion(req.params.nom, user.id);
      const code = question.getCours();

      res.render("question/reformuler-question", {
        title: `${titreBase}`,
        user: user,
        code: code,
        question: question
      });
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  public async visualiserQuestions(
    req: Request,
    res: Response,
    next: NextFunction
  ) {
    try {
      const code = req.params.code;
      const user = req.body.user as Enseignant;
      const questionMap: Map<string, Question> =
        questionControleur.recupererQuestions();
      let questionArr = [];

      questionMap.forEach((val, key) => {
        if (val.getCours() === code
            && val.getEnseignant() === user.id) {
          questionArr.push({
            nom: val.getNom(),
            cours: val.getCours(),
            categorie: val.getCategorie(),
            user: val.getEnseignant()
          });
        }
      });
      
      res.render("question/questions", {
        title: `${titreBase}`,
        user: user,
        code: code,
        questions: questionArr
      });
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  public async visualiserToutesQuestions(
    req: Request,
    res: Response,
    next: NextFunction
  ) {
    try {
      const user = req.body.user as Enseignant;
      const questionMap: Map<string, Question> =
        questionControleur.recupererQuestions();
      let questionArr = [];

      questionMap.forEach((val, key) => {
        if (val.getEnseignant() === user.id) {
          questionArr.push({
            nom: val.getNom(),
            cours: val.getCours(),
            categorie: val.getCategorie(),
            user: val.getEnseignant()
          });
        }
      });

      res.render("question/toutes-questions", {
        title: `${titreBase}`,
        user: user, 
        questions: questionArr,
      });
    } catch (error) {
      req.flash("error", `ERREUR QUESTION`);
      res.redirect("/");
      this._errorCode500(error, req, res);
    }
  }

  public async detaillerQuestion(
    req: Request,
    res: Response,
    next: NextFunction
  ) {
    try {
      const nom: string = req.params.nom;
      const user = req.body.user as Enseignant;

      const question: Question = questionControleur.recupererQuestion(req.params.nom, user.id);

      console.trace(question);
      res.render(`question/details-question`, {
        title: `${titreBase}`,
        user: user,
        question: question,
      });
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  public async ajouterQuestions(req: Request, res: Response, next: NextFunction) {
    const user = req.body.user as Enseignant;
    const {
      cours,
      categorie,
      nom,
      enonce,
      reponse,
      retroactionPositive,
      retroactionNegative,
    } = req.body;

    console.trace("créer question");
    console.trace(req.body);

    try {
      questionControleur.ajouterQuestion(
        cours,
        categorie,
        nom,
        enonce,
        reponse,
        retroactionPositive,
        retroactionNegative,
        user ? user.id : "error"
      );
      req.flash("info", `Nouvelle question : ${nom}`);
      res.redirect(`/questions/formuler-question/${cours}`);
    } catch (error) {
      if (error.message.includes("existe déjà")) {
        console.warn(error.message);
        req.flash("error", `Une question avec le nom "${nom}" existe déjà`);
        res.redirect(`/questions/formuler-question/${cours}`);
      }
      else if(error.message.includes("ne peut pas etre vide")) {
        console.warn(error.message);
        req.flash("error", `Le nom de la question ne peut pas être vide`);
        res.redirect(`/questions/formuler-question/${cours}`);
      }
      else {
        this._errorCode500(error, req, res);
      }
    }
  }

  public async modifierQuestion(req: Request, res: Response, next: NextFunction) {
    const user = req.body.user as Enseignant;
    const {
      ancienNom,
      cours,
      categorie,
      nom,
      enonce,
      reponse,
      retroactionPositive,
      retroactionNegative,
    } = req.body;

    console.trace("modifier question");
    console.trace(req.body);

    try {
      questionControleur.modifierQuestion(
        ancienNom,
        cours,
        categorie,
        nom,
        enonce,
        reponse,
        retroactionPositive,
        retroactionNegative,
        user ? user.id : "error"
      );
      req.flash("info", `Modifier Question: ${nom}`);
      res.redirect(`/questions/reformuler-question/${nom}`);
    } catch (error) {
      if (error.message.includes("existe déjà")) {
        console.warn(error.message);
        req.flash("error", `Une question avec le nom "${nom}" existe déjà`);
        res.redirect(`/questions/reformuler-question/${nom}`);
      } else {
        this._errorCode500(error, req, res);
      }
    }
  }

  public async supprimerQuestion(req: Request, res: Response, next: NextFunction) {
    const user = req.body.user as Enseignant;

    const nom = req.params.nom;
    const code = questionControleur.recupererQuestion(req.params.nom, user.id).getCours();

    console.trace("supprimer question");
    console.trace(req.body);

    try {
      questionControleur.supprimerQuestion(nom, user);
      req.flash("info", `Supprimer Question: ${nom}`);
      res.redirect(`/questions/questions/${code}`);
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  public async question(req: Request, res: Response, next: NextFunction) {
    try {
      const user = req.body.user as Enseignant;
      const code = req.params.code;
      res.render("question", {
        title: `${titreBase}`,
        user: user,
        code: code,
      });
    } catch (error) {
      this._errorCode500(error, req, res);
    }
  }

  private init() {
    this._router.get("/questionnaires", authenticate, this.questionnaires.bind(this));
    this._router.get("/cours-actifs", authenticate, this.visualiserCoursActifs.bind(this));
    this._router.get(
      "/formuler-question/:code", authenticate,
      this.formulerQuestion.bind(this)
    );
    this._router.post("/creer-question", authenticate, this.ajouterQuestions.bind(this));
    this._router.get("/questions/:code", authenticate, this.visualiserQuestions.bind(this));
    this._router.get(
      "/toutes-questions", authenticate,
      this.visualiserToutesQuestions.bind(this)
    );
    this._router.get(
      "/details-question/:nom", authenticate,
      this.detaillerQuestion.bind(this)
    );
    this._router.get("/question/:code", authenticate, this.question.bind(this));
    this._router.get("/reformuler-question/:nom", authenticate, this.reformulerQuestion.bind(this));
    this._router.post("/modifier-question", authenticate, this.modifierQuestion.bind(this));
    this._router.post("/supprimer-question/:nom", authenticate, this.supprimerQuestion.bind(this));
  }
}

export const questionRouter = new QuestionRouter();
