const { isAPIKeyUser } = require("../../middlewares/accessValidator");
const routes = require("express").Router();

const SchemaValidator = require("../../middlewares/schemaValidator");

const FieldMiddleware = require("../../middlewares/fields");

const authController = require("../auth/auth.controller");
const eventController = require("./event.controller");
const eventInscriptionController = require("./events_inscriptions.controller");
const eventReservationController = require("./events_reservations.controller");
const eventValidation = require("./event.validations");

const { cacheSuccesses } = require("../../middlewares/cache");

const SortMiddleware = require("../../middlewares/sort");

const entityController = require("../entities/entity.controller");

const generalInvalidFields = [
  "userId",
  "createdAt",
  "updatedAt",
  "assistants",
  "confirmed",
  "allow_multiple",
  "overflow_eventId",
  "state",
  "confirmed",
  "multiple_limit",
  "marketing_list",
  "state",
  "contact_person",
  "contact_email",
  "createdAt",
  "updatedAt",
  "gmt",
  "url_streaming",
  "url_poll",
  "url_registration",
  "featured",
  "virtual",
  "allow_questions",
  "assistanceType",
  "assistanceTypeText",
  "allow_overflow",
  "typeId",
  "venueId",
  "locationId",
  "sold_out",
  "level",
];

const eventDetailsFields = [
  "id",
  "name",
  "description",
  "stateCode",
  "stateText",
  "campaign_text",
  "init_date",
  "end_date",
];

/**
 * @api {get} /api/v4/web/events Obtener Eventos Disponibles (GetAvailableEvents)
 * @apiName GetAvailableEvents
 * @apiGroup Eventos
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint devuelve una lista de eventos disponibles, incluyendo su estado de aforo.
 *
 * @apiSuccess {Object[]} events Lista de eventos disponibles.
 * @apiSuccess {String} events.id Identificador único del evento.
 * @apiSuccess {String} events.name Nombre del evento.
 * @apiSuccess {Object} events.location Ubicación del evento.
 * @apiSuccess {String} events.location.country País donde se realiza el evento.
 * @apiSuccess {String} events.location.city Ciudad donde se realiza el evento.
 * @apiSuccess {String} events.location.country_code Código del país del evento.
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta:
 * [
 *   {
 *     "id": "03f70b2d-53c5-11ed-9b36-000c29a89113",
 *     "name": "Madrid 2022 - 16ª Edición",
 *     "location": {
 *       "country": "España",
 *       "city": "Madrid",
 *       "country_code": "ES"
 *     },
 *   },
 *   {
 *     "id": "b518e0f7-b2d1-11ed-9477-000c29e7c50f",
 *     "name": "Sevilla 2023 - 22ª Edición",
 *     "location": {
 *       "country": "España",
 *       "city": "Sevilla",
 *       "country_code": "ES"
 *     },
 *   }
 * ]
 */
routes.get(
  "/web/events/",
  isAPIKeyUser,
  FieldMiddleware.middleware({
    validFields: ["id", "name"],
  }),

  (req, res, next) => {
    const scopes = ["defaultScope", "withOpenInscriptions"];
    res.locals.v4 = { removeFields: ["partners", "speakers", "details", "multimedias", "type"] };
    return eventController.find({ scopes })(req, res, next);
  }
);

/**
 * @api {get} /api/v4/web/events/:eventId Obtener Datos del Evento (GetEventDetails)
 * @apiName GetEventDetails
 * @apiGroup Eventos
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint devuelve los detalles de un evento específico.
 *
 * @apiParam {String} eventId Identificador único del evento.
 *
 * @apiSuccess {String} stateCode Código del estado del evento.
 * @apiSuccess {String} stateText Descripción del estado del evento.
 * @apiSuccess {String} id Identificador único del evento.
 * @apiSuccess {String} name Nombre del evento.
 * @apiSuccess {String} description Descripción del evento.
 * @apiSuccess {String} campaign_text Texto de campaña (si aplica).
 * @apiSuccess {String} init_date Fecha y hora de inicio del evento (ISO 8601).
 * @apiSuccess {String} end_date Fecha y hora de finalización del evento (ISO 8601).
 * @apiSuccess {Object} location Ubicación del evento.
 * @apiSuccess {String} location.country País donde se realiza el evento.
 * @apiSuccess {String} location.city Ciudad donde se realiza el evento.
 * @apiSuccess {String} location.country_code Código del país del evento.
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta:
 * {
 *   "stateCode": "registrations_open",
 *   "stateText": "Inscripciones abiertas",
 *   "id": "03f70b2d-53c5-11ed-9b36-000c29a89113",
 *   "name": "Madrid 2022 - 16ª Edición",
 *   "description": "Palacio Municipal de Congresos de Madrid, Campo de las Naciones, Avenida de la Capital de España s/n\n\nENTREGA PREMIO ALGO+Q1 CANCIÓN",
 *   "campaign_text": "",
 *   "init_date": "2024-08-29T00:00:00.000Z",
 *   "end_date": "2024-12-01T14:30:00.000Z",
 *   "location": {
 *   "country": "España",
 *   "city": "Madrid",
 *   "country_code": "ES"
 *   },
 * }
 */

routes.get(
  "/web/events/:id",
  isAPIKeyUser,
  FieldMiddleware.middleware({
    validFields: eventDetailsFields,
    invalidFields: generalInvalidFields,
  }),
  (req, res, next) => {
    const scopes = ["defaultScope"];
    res.locals.v4 = {
      removeFields: [
        "partners",
        "speakers",
        "details",
        "multimedias",
        "type",
        "sold_out",
        "init_available_date",
        "end_available_date",
      ],
    };
    return eventController.findOne({ scopes })(req, res, next);
  }
);

/**
 * @api {get} /api/v4/web/events/:id/check_capacity?group_size=xx Verificar Capacidad del Evento (CheckEventCapacity)
 * @apiName CheckEventCapacity
 * @apiGroup Eventos
 * @apiVersion 4.0.0
 * @apiDescription Determina si hay aforo suficiente para el tamaño de grupo que se ha indicado.
 *
 * @apiParam {String} id ID único del evento.
 * @apiParam {Number} [group_size=10] Tamaño del grupo para el cual se verifica el aforo (Parámetro de consulta).
 *
 * @apiSuccess {String} eventId ID único del evento.
 * @apiSuccess {Number} group_size Tamaño del grupo para el cual se verifica el aforo.
 * @apiSuccess {Boolean} allow Indica si el grupo puede inscribirse al evento.
 * @apiSuccess {Boolean} allow_overflow Indica si el grupo puede inscribirse a la lista de espera del evento.
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta:
 *     HTTP/1.1 200 OK
 *     {
 *       "eventId": "03f70b2d-53c5-11ed-9b36-000c29a89113",
 *       "group_size": 1,
 *       "allow": true
 *       "allow_overflow": true
 *     }
 */

routes.get(
  "/web/events/:id/check_capacity",
  isAPIKeyUser,
  FieldMiddleware.middleware({
    invalidFields: generalInvalidFields,
  }),
  (req, res, next) => {
    res.locals.v4 = {
      removeFields: [
        "assistants",
        "confirmed",
        "sold_out",
        "assistants_overflow",
        "confirmed_overflow",
        "sold_out_overflow",
      ],
    };
    return eventController.checkCapacity(req, res, next);
  }
);

/**
 * @api {get} /api/v4/web/reservations/code/:encodedCode Recupera la reserva asociada al Código de Invitación (GetReservationFromCode)
 * @apiName GetReservationFromCode
 * @apiGroup Eventos
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint verifica un código de reserva devolviendo al evento y entidad a la que pertenece. El código de invitación está codificado en Base64.
 *
 * @apiParam {String} encodedCode Código de invitación codificado en Base64. Ejemplo, el código "MD22-4939" se codifica como "TUQyMi00OTM5"
 *
 * @apiSuccess {String} id indica si el Id de la reserva.
 * @apiSuccess {String} stateText indica la situación de la reserva.
 * @apiSuccess {String} code el código de la reserva sin codificar.
 * @apiSuccess {String} eventId indica el id del evento al que pertenece la reserva.
 * @apiSuccess {String} eventName indica el nombre del evento al que pertenece la reserva.
 * @apiSuccess {String} entityId indica el id de la entidad a la que pertenece la reserva.
 * @apiSuccess {String} entityName indica el nombre de la entidad a la que pertenece la reserva.
 *
 * @apiError (Error 404) NotFound Código de reserva no encontrado.
 * 
 * @apiErrorExample {json} Ejemplo de Respuesta Fallida:
 *     HTTP/1.1 404 Not Found
 *     {
 *       "message": "Código de reserva no encontrado"
 *     }
 * @apiSuccessExample {json} Ejemplo de Respuesta Exitosa:
 *     HTTP/1.1 200 OK
 *     {
 *     "id": "d8af01cf-b86d-4e10-9c84-442cd31a7fb8",
 *     "stateText": "Inscripciones abiertas a la reserva",
 *     "code": "MAD24DEF218",
 *     "eventId": "84613446-765a-11ef-9b46-000c29a89113",
 *     "eventName": "Madrid 2024 - 18ª Edición",
 *     "entityId": "a015dcef-8213-11ee-9b36-000c29a89113",
 *     "entityName": "Alianza para la FP Dual - Barcelona"
 *     }
 */


routes.get(
  "/web/reservations/code/:code",
  isAPIKeyUser,
  FieldMiddleware.middleware({
    invalidFields: generalInvalidFields,
  }),
  (req, res, next) => {
    res.locals.v4 = {
      removeFields: [
        "assistanceType",
        "assistanceTypeText",
        "state",
      ],
    };
    return eventReservationController.getReservationFromCode(req, res, next);
  }
);



/**
 * @api {get} /api/v4/web/events/:eventId/reservations/:encodedCode Verificar Código de Invitación (CheckInvitationCode)
 * @apiName CheckInvitationCode
 * @apiGroup Eventos
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint verifica si un código de invitación es aplicable a un evento concreto. El código de invitación está codificado en Base64.
 *
 * @apiParam {String} eventId Identificador único del evento.
 * @apiParam {String} encodedCode Código de invitación codificado en Base64. Ejemplo, el código "MD22-4939" se codifica como "TUQyMi00OTM5"
 *
 * @apiSuccess {Boolean} applicable Indica si el código de invitación es aplicable (true) o no (false).
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta Exitosa:
 *     HTTP/1.1 200 OK
 *     true
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta Fallida:
 *     HTTP/1.1 200 OK
 *     false
 */

routes.get(
  "/web/events/:id/reservations/:encodedInvitationCode",
  isAPIKeyUser,
  eventReservationController.checkReservationCode
);

/**
 * @api {post} /api/v4/web/events/:eventId/inscriptions/ Dar de Alta una Inscripción (CreateEventInscription)
 * @apiName CreateEventInscription
 * @apiGroup Inscriptions
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint permite registrar una inscripción a un evento específico.
 *
 * @apiParam {String} eventId Identificador único del evento.
 *
 * @apiBody {String} code Código opcional para la inscripción - Si viene código.
 * @apiBody {String} email Email del participante, debe ser válido.
 * @apiBody {String} name Nombre del participante.
 * @apiBody {String} Apellido del participante.
 * @apiBody {String} profile Tipo de participante (student/tutor/guest/free).
 * @apiBody {String} country País del participante (ES/MX).
 * @apiBody {String} [entityId] Entidad del participante - Opcional - solo si son student/tutor/guest.*
 * @apiBody {number} [group_size] Cantidad participantes a solicitar - Opcional - solo si son tutores.*
 *
 *
 * @apiSuccess {String} id ID de la inscripción.
 * @apiSuccess {String} stateText Estado de la inscripción.
 * @apiSuccess {String} type Tipo de asistencia.
 * @apiSuccess {String} code_ticket Código del ticket generado.
 * @apiSuccess {Boolean} validated Estado de validación de la inscripción.
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta 1:
 * ENVIO
 * {
 *   "code" : "B24URD397",
 *  "email" : "rbrrbr2005@gmail.com",
 *  "name" : "aaa",
 *  "surname" : "a",
 *  "profile": "student",
 *  "country": "ES",
 * }
 * RESPUESTA
 * {
 *   "id": "003fb9ae-a8e7-41dc-802b-15dc0e1d4702",
 *   "stateText": "Inscripción confirmada",
 *   "type": "onsite group",
 *   "code_ticket": "ENT-02220012",
 *   "validated": true
 * }
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta 2:
 * ENVIO
 * {
 *  "code" : "BIL24-DEF219", - Reserva en lista de espera
 *  "email" : "rbrrbr20067@gmail.com",
 *  "name" : "aaa",
 *  "surname" : "a",
 *  "profile": "studient",
 * }
 * RESPUESTA
 * {
 *   "id": "002610be-96bb-4f56-91fc-c181d354beeb",
 *   "stateText": "Reserva pendiente de confirmaci\xF3n",
 *   "type": "onsite group",
 *   "code_ticket": "ENT-60030638",
 *   "validated": false
 * }
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta 3: Profesor solicita una reserva grupal
 * ENVIO
 * {
 *   "code" : "",
 *   "email" : "rbrrbr20167@gmail.com",
 *   "name" : "aaa",
 *   "surname" : "a",
 *   "profile": "tutor",
 *   "country": "ES",
 *   "entityId": "757e6018-af85-11e9-aa90-000c295f0f58",
 *   "group_size": 5
 * }
 * RESPUESTA
 * {
      "id": "00011602-8345-46e6-8c2a-7a54214cf526",
 *    "stateText": "Reserva pendiente de confirmaci\xF3n",
 *    "type": "onsite group",
 *    "code_ticket": "ENT-19161191",
 *    "validated": false
 * }
 */

routes.post(
  "/web/events/:id/inscriptions",
  isAPIKeyUser,

  SchemaValidator(eventValidation.webv4InscriptionInputType, true),
  //Prepara los datos de la inscripción tipo ....
  eventInscriptionController.prepareDataInscription,
  //Recupera la reservation si viene
  eventReservationController.recuperateReservationByCode,
  //Recupera a registra el usuario que se va a inscribir
  authController.getOrCreateUser,
  //Comprobamos si tiene ya una incripción, en tal caso, comprobamos el código de reserva sea el de la inscripcion hecha,
  //si no es así es el caso de un usuario que se reinscribe con otro código de reserva
  eventInscriptionController.checkInscriptionByUser,
  //Si es un usuario tutor y solicita un group_size se crea la reserva
  eventReservationController.createReservationToEntity,
  eventReservationController.activeReservationToEntity,

  (req, res, next) => {
    res.locals.v4 = {
      removeFields: [
        "reservation",
        "eventId",
        "date",
        "userId",
        "source",
        "reservationId",
        "overflowEventId",
        "updatedAt",
        "createdAt",
      ],
    };
    if (res.locals.dataInscription.reservation) {
      console.log(">>>>>>>Incripcion con reserva");
      eventReservationController.createInscriptionReservation(req, res, next);
    } else {
      console.log(">>>>>>>Incripcion sin reserva");
      eventInscriptionController.createInscription(req, res, next);
    }
    //next();
  }
  //  eventInscriptionController.createInscriptionMarketingList
);

/**
 * @api {get} /api/v4/web/events/:id/inscriptions/:email Comprobar Inscripción (CheckInscription)
 * @apiName CheckInscription
 * @apiGroup Inscriptions
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint verifica si el correo electrónico proporcionado tiene una inscripción para el evento concreto.
 *
 * @apiParam {String} id Identificador único del evento.
 * @apiParam {String} email Correo electrónico a comprobar.
 *
 * @apiSuccess {String} message Mensaje que indica el estado de la inscripción.
 * @apiSuccessExample {json} Ejemplo de Respuesta Exitosa:
 *     HTTP/1.1 200 OK
 *     {
 *       "message": "Inscripción confirmada"
 *     }
 *
 * @apiError (Error 404) NotFound No hay inscripción con el correo electrónico proporcionado.
 * @apiErrorExample {json} Ejemplo de Respuesta Fallida:
 *     HTTP/1.1 404 Not Found
 *     {
 *       "message": "No hay inscripción con ese email"
 *     }
 */
// Comprobar si estoy inscrito al congreso por la web
routes.get("/web/events/:id/inscriptions/:email", isAPIKeyUser, eventInscriptionController.checkInscriptionByMail);

/**
 * @api {get} /api/v4/web/inscriptions/:id Obtener datos de la Inscripción (GetInscription)
 * @apiName GetInscription
 * @apiGroup Inscriptions
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint devuelve la inscripción correspondiente al id proporcionado.
 *
 * @apiParam {String} id Identificador único de la inscripcion.
 *
 * @apiSuccess {String} message datos de la inscripción.
 * @apiSuccessExample {json} Ejemplo de Respuesta Exitosa:
 *     HTTP/1.1 200 OK
 *     {
 *      "id": "4043a096-f598-4dba-b34e-ac96fdbd1b0a",
 *      "stateText": "Inscripción confirmada",
 *      "code_ticket": "ENT-87491914",
 *      "eventName": "Bilbao 2024 - XVI Edición",
 *      "userName": "aaa",
 *      "userSurname": "a"
 *     }
 *
 * @apiError (Error 404) NotFound No hay inscripción con el id proporcionado.
 * @apiErrorExample {json} Ejemplo de Respuesta Fallida:
 *     HTTP/1.1 404 Not Found
 *     {
 *       "message": "Inscripción no encontrada"
 *     }
 */
// Esto da la inscripción de un usuario
routes.get("/web/inscriptions/:id", isAPIKeyUser,
  FieldMiddleware.middleware({
  }),
  (req, res, next) => {
    res.locals.v4 = {
      removeFields: [
        "code_ticket_qr",
      ],
    };
    return eventInscriptionController.getInscription(req, res, next);
  }  
  );
/**
 *
 * @api {delete} /api/v4/web/inscriptions/:id Eliminar inscripcion (DeleteInscription)
 * @apiName DeleteInscription
 * @apiGroup Inscriptions
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint elimina inscripción.
 *
 * @apiParam {String} id Identificador único de la inscripcion.
 *
 * @apiSuccess {String} message Mensaje que indica resultado.
 * @apiSuccessExample {json} Ejemplo de Respuesta Exitosa:
 *     HTTP/1.1 200 OK
 *     {
 *       "message": "Inscripción eliminada"
 *     }
 *
 * @apiError (Error 404) NotFound Error al eliminar inscripción.
 * @apiErrorExample {json} Ejemplo de Respuesta Fallida:
 *     HTTP/1.1 404 Not Found
 *     {
 *       "message": "Error al eliminar inscripción"
 *     }
 */
// Borrar una inscripción
routes.delete("/web/inscriptions/:id", isAPIKeyUser, eventInscriptionController.deleteInscription);

/**
 * @api {get} /api/v4/web/entities/colleges Lista de Entidades Educativas (GetColleges)
 * @apiName GetColleges
 * @apiGroup Entidades
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint devuelve una lista de entidades educativas, incluyendo su nombre, nivel y país.
 *
 * @apiSuccess {Object[]} colleges Lista de entidades educativas.
 * @apiSuccess {String} colleges.id Identificador único de la entidad educativa.
 * @apiSuccess {String} colleges.name Nombre de la entidad educativa.
 * @apiSuccess {String} colleges.country Código de país de la entidad educativa.
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta:
 * [
 *   {
 *     "id": "757de756-af85-11e9-aa90-001c295f0f58",
 *     "name": "Academia  Santa Teresa Málaga",
 *     "country": "ES"
 *   },
 *   {
 *     "id": "7583028a-af85-11e9-aa90-000c395f0f58",
 *     "name": "Academia Díaz Balaguer",
 *     "country": "ES"
 *   },
 *   {
 *     "id": "758196a7-af85-11e9-aa90-000c294f0f58",
 *     "name": "Agora Portals International School - Islas Baleares",
 *     "country": "ES"
 *   },
 * ]
 */

routes.get(
  "/web/entities/colleges",
  isAPIKeyUser,
  //cacheSuccesses("24 hours"),
  FieldMiddleware.middleware({
    invalidFields: generalInvalidFields,
  }),
  SortMiddleware.middleware({ default: "name" }),
  entityController.find({
    scopes: ["defaultScope", "onlyColleges"],
  })
);

/**
 * @api {get} /api/v4/web/entities/partners Lista de Partners (GetPartners)
 * @apiName GetPartners
 * @apiGroup Partners
 * @apiVersion 4.0.0
 * @apiDescription Este endpoint devuelve una lista de partners disponibles, incluyendo su nombre, nivel y país.
 *
 * @apiSuccess {Object[]} partners Lista de partners disponibles.
 * @apiSuccess {String} partners.id Identificador único del partner.
 * @apiSuccess {String} partners.name Nombre del partner.
  * @apiSuccess {String} partners.country Código del país del partner.
 *
 * @apiSuccessExample {json} Ejemplo de Respuesta:
 * [
 *   {
        "id": "7dfc4513-ce5b-11e9-8055-000c29a89613",
        "name": "ABC",
         "country": "ES"
    },
    {
        "id": "3c7950ac-48b4-11ee-9b36-000c29a59113",
        "name": "AECC",
         "country": "ES"
    },
    {
        "id": "2b43d32b-d4d1-11e9-8055-000c29a69113",
        "name": "AGR FOOD MARKETING",
         "country": "ES"
    },
    {
        "id": "6c2df93f-af83-11e9-aa90-000c29ef0f58",
        "name": "CAIXABANK",
        "country": "ES"
    },
 *   ...
 * ]
 */

routes.get(
  "/web/entities/partners",
  isAPIKeyUser,
  //cacheSuccesses("24 hours"),
  FieldMiddleware.middleware({
    invalidFields: generalInvalidFields,
  }),
  SortMiddleware.middleware({ default: "name" }),
  entityController.find({
    scopes: ["defaultScope", "onlyPartners"],
  })
);

module.exports = routes;
