"use strict";
const moment = require("moment");
const Sequelize = require("sequelize");
moment.locale("es");

const getStateCode = (event) => {
  var currentDate = moment(),
    initDate = moment(event.init_date),
    endDate = moment(event.end_date),
    init_availableDate = moment(event.init_available_date),
    end_availableDate = moment(event.end_available_date);

  if (currentDate.isBetween(initDate, endDate)) {
    return "current_event";
  } else {
    if (endDate.isBefore(currentDate)) {
      return "closed_event";
    } else {
      if (currentDate.isBefore(init_availableDate)) {
        return "future_registrations";
      } else {
        if (currentDate.isBetween(init_availableDate, end_availableDate)) {
          if (event.url_registration) {
            return "url_registrations_open";
          } else {
            return event.sold_out == 1 ? "waitinglist_open" : "registrations_open";
          }
        } else {
          if (currentDate.isAfter(end_availableDate)) return "closed_registrations";
          else return "N/A";
        }
      }
    }
  }
};

const getStateText = (event) => {
  var currentDate = moment(),
    initDate = moment(event.init_date),
    endDate = moment(event.end_date),
    init_availableDate = moment(event.init_available_date),
    end_availableDate = moment(event.end_available_date);

  if (currentDate.isBetween(initDate, endDate)) {
    return "Congreso en curso";
  } else {
    if (endDate.isBefore(currentDate)) {
      return "Congreso finalizado";
    } else {
      if (currentDate.isBefore(init_availableDate)) {
        return "Inscripciones a partir del " + init_availableDate.format("D [de] MMMM");
      } else {
        if (currentDate.isBetween(init_availableDate, end_availableDate)) {
          if (event.url_registration) {
            return "Inscripciones abiertas";
          } else {
            return event.sold_out == 1 ? "Inscripciones abiertas a lista de espera" : "Inscripciones abiertas";
          }
        } else {
          if (currentDate.isAfter(end_availableDate)) return "Inscripciones cerradas";
          else return "N/A";
        }
      }
    }
  }
};

const getAssistanceType = (event) => {
  if (event.virtual) {
    if (event.assistants > 0) {
      return "onsite, online";
    } else {
      return "online";
    }
  } else {
    return "onsite";
  }
};

const getAssistanceTypeText = (event) => {
  if (event.virtual) {
    if (event.assistants > 0) {
      return "evento presencial y online";
    } else {
      return "evento online";
    }
  } else {
    return "evento presencial";
  }
};

module.exports = function (sequelize, DataTypes) {
  const Event = sequelize.define(
    "Event",
    {
      id: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
        primaryKey: true,
      },
      name: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      description: {
        type: DataTypes.STRING,
      },
      campaign_text: {
        type: DataTypes.TEXT,
        allowNull: true,
      },
      init_date: {
        type: DataTypes.DATE,
        allowNull: false,
      },
      end_date: {
        type: DataTypes.DATE,
      },
      init_available_date: {
        type: DataTypes.DATE,
      },
      end_available_date: {
        type: DataTypes.DATE,
      },
      gmt: {
        type: DataTypes.INTEGER,
        defaultValue: 1,
      },
      assistants: {
        type: DataTypes.INTEGER,
      },
      confirmed: {
        type: DataTypes.INTEGER,
      },
      sold_out: {
        //Se han vendido todas y se ha abierto lista de espera si hay asignada
        type: DataTypes.BOOLEAN,
        defaultValue: false,
      },
      allow_multiple: {
        type: DataTypes.BOOLEAN,
        allowNull: false,
        defaultValue: false,
      },
      multiple_limit: {
        type: DataTypes.INTEGER,
      },
      allow_overflow: {
        type: DataTypes.BOOLEAN,
        allowNull: false,
        defaultValue: false,
      },
      overflow_eventId: {
        type: DataTypes.UUID,
        foreignKey: true,
        require: false,
      },
      state: {
        type: DataTypes.STRING,
        allowNull: false,
        defaultValue: "draft",
      },
      stateCode: {
        type: Sequelize.VIRTUAL(Sequelize.STRING, [
          "init_date",
          "end_date",
          "init_available_date",
          "end_available_date",
          "sold_out",
        ]),
        get: function () {
          return getStateCode(this);
        },
      },
      stateText: {
        type: Sequelize.VIRTUAL(Sequelize.STRING, [
          "init_date",
          "end_date",
          "init_available_date",
          "end_available_date",
          "sold_out",
        ]),
        get: function () {
          return getStateText(this);
        },
      },
      typeId: {
        type: DataTypes.UUID,
        foreignKey: true,
      },
      venueId: {
        type: DataTypes.UUID,
        foreignKey: true,
      },
      locationId: {
        type: DataTypes.UUID,
        foreignKey: true,
      },
      url_streaming: {
        type: DataTypes.STRING,
      },
      url_poll: {
        type: DataTypes.STRING,
      },
      url_registration: {
        type: DataTypes.STRING,
      },
      marketing_list: {
        type: DataTypes.STRING,
      },
      userId: {
        type: DataTypes.UUID,
        foreignKey: true,
      },
      featured: {
        type: DataTypes.BOOLEAN,
        defaultValue: false,
      },
      virtual: {
        type: DataTypes.BOOLEAN,
        defaultValue: false,
      },
      allow_questions: {
        type: DataTypes.BOOLEAN,
        defaultValue: true,
      },
      assistanceType: {
        type: Sequelize.VIRTUAL(Sequelize.STRING, ["virtual", "assistants"]),
        get: function () {
          return getAssistanceType(this);
        },
      },
      assistanceTypeText: {
        type: Sequelize.VIRTUAL(Sequelize.STRING, ["virtual", "assistants"]),
        get: function () {
          return getAssistanceTypeText(this);
        },
      },
    },
    {
      tableName: "events",
      freezeTableName: true,
      timestamps: true,

      defaultScope: {
        where: {
          state: "publish",
          typeId: { [Sequelize.Op.ne]: 2 },
        },
        include: [
          {
            model: sequelize.models.EventType,
            as: "type",
            attributes: ["name", "title"],
          },
          {
            association: "location",
            attributes: ["country", "city", "country_code"],
            require: false,
          },
        ],
      },
    }
  );

  Event.associate = function (models) {
    Event.OverflowEvent = Event.belongsTo(models.Event, {
      as: "overflowEvent",
      foreignKey: "overflow_eventId",
      required: false,
    });

    Event.Type = Event.belongsTo(models.EventType, { foreignKey: "typeId", as: "type" });
    Event.UserCreate = Event.belongsTo(models.User, { foreignKey: "userId", as: "user" });
    Event.Venue = Event.belongsTo(models.Venue, { foreignKey: "venueId", as: "venue", required: false });
    Event.Details = Event.hasMany(models.EventDetail, { foreignKey: "eventId", as: "details" });
    Event.Location = Event.belongsTo(models.Location, { foreignKey: "locationId", as: "location" });

    //OJO antes de force comentar
    // OJO GENERA UN FOREIGN KEY Con eventos y habrá ID de otras entidades que no exitan en la tabla eventos, porque son post o speakers
    Event.Comments = Event.hasMany(models.Comment, {
      foreignKey: "entityId",
      scope: {
        entityName: "event",
      },
      as: "comments",
      required: false,
    });

    Event.Multimedias = Event.hasMany(models.Multimedia, {
      foreignKey: "entityId",
      as: { singular: "multimedia", plural: "multimedias" },
      required: false,
    });

    Event.Reservations = Event.hasMany(models.EventReservation, {
      foreignKey: "eventId",
      as: "reservations",
      required: false,
    });
    Event.Inscriptions = Event.hasMany(models.EventInscription, {
      foreignKey: "eventId",
      as: "inscriptions",
      required: false,
    });
    Event.Questions = Event.hasMany(models.EventQuestion, {
      foreignKey: "eventId",
      as: "questions",
      required: false,
    });
  };

  Event.addScope("featured", {
    where: {
      featured: true,
    },
  });

  Event.addScope("includeVenue", () => {
    return {
      include: [{ model: sequelize.models.Venue, as: "venue" }],
    };
  });

  Event.addScope("includeMultimedias", () => {
    return {
      include: [
        {
          model: sequelize.models.Multimedia,
          as: { singular: "multimedia", plural: "multimedias" },
          required: false,
          include: [
            {
              model: sequelize.models.MultimediaFile,
              as: "multimediaFile",
            },
          ],
          order: [["type", "ASC"]], // <- esto no funciona por ahora en Sequelize
        },
      ],
    };
  });

  Event.addScope("includeMultimediaAvatar", () => {
    return {
      include: [
        {
          model: sequelize.models.Multimedia,
          as: { singular: "multimedia", plural: "multimedias" },
          where: { type: "avatar" },
          required: false,
          include: [
            {
              model: sequelize.models.MultimediaFile,
              as: "multimediaFile",
            },
          ],
        },
      ],
    };
  });

  Event.addScope("includeInscription", (userId) => {
    return {
      include: [
        { model: sequelize.models.EventInscription, as: "inscriptions", required: false, where: { userId: userId } },
      ],
    };
  });

  Event.addScope("includeOverflowEvent", () => {
    return {
      include: [
        {
          model: sequelize.models.Event,
          as: "overflowEvent",
          required: false,
          where: { typeId: { [Sequelize.Op.ne]: null } },
          //                  attributes: ['assistants', 'confirmed'],
        },
      ],
    };
  });

  Event.addScope("includeDetails", () => {
    return {
      include: [
        {
          model: sequelize.models.EventDetail,
          as: "details",
          required: false,
          include: [
            {
              model: sequelize.models.Speaker,
              as: "speaker",
              required: false,
              include: [
                {
                  model: sequelize.models.Multimedia,
                  as: { singular: "multimedia", plural: "multimedias" },
                  required: false,
                  include: [
                    {
                      model: sequelize.models.MultimediaFile,
                      as: "multimediaFile",
                    },
                  ],
                },
              ],
            },
          ],
        },
      ],
    };
  });

  Event.addScope("includeComments", () => {
    return {
      include: [
        {
          model: sequelize.models.Comment,
          as: "comments",
          required: false,
          include: [
            {
              model: sequelize.models.User,
              as: "user",
            },
          ],
        },
      ],
    };
  });

  Event.addScope("next", {
    where: {
      init_date: {
        [Sequelize.Op.gte]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
      },
    },
  });

  Event.addScope("today", {
    where: {
      init_date: {
        [Sequelize.Op.gte]: moment().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
        [Sequelize.Op.lt]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
      },
    },
  });

  Event.addScope("current", {
    where: {
      init_date: {
        [Sequelize.Op.lte]: moment().format("YYYY-MM-DD HH:mm:ss"),
      },
      end_date: {
        [Sequelize.Op.gt]: moment().format("YYYY-MM-DD HH:mm:ss"),
      },
    },
  });

  Event.addScope("tomorrow", {
    where: {
      init_date: {
        [Sequelize.Op.gte]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
        [Sequelize.Op.lt]: moment().add(2, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
      },
    },
  });

  Event.addScope("yesterday", {
    where: {
      init_date: {
        [Sequelize.Op.gte]: moment().add(-1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
        [Sequelize.Op.lt]: moment().add("day").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
      },
    },
  });

  Event.addScope("past", {
    where: {
      init_date: {
        [Sequelize.Op.lt]: moment().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
      },
    },
  });

  Event.addScope("withOpenInscriptions", {
    where: {
      init_available_date: {
        [Sequelize.Op.lte]: moment().format("YYYY-MM-DD HH:mm:ss"),
      },
      end_available_date: {
        [Sequelize.Op.gt]: moment().format("YYYY-MM-DD HH:mm:ss"),
      },
    },
  });

  Event.addScope("CitiesOfEvents", () => {
    return {
      include: [
        {
          model: sequelize.models.Location,
          as: "location",
          required: false,
          include: [
            {
              model: sequelize.models.Multimedia,
              as: { singular: "multimedia", plural: "multimedias" },
              required: false,
              attributes: ["type"],
              include: [
                {
                  model: sequelize.models.MultimediaFile,
                  as: "multimediaFile",
                  attributes: ["name", "description", "class", "provider", "url"],
                },
              ],
            },
          ],
        },
        { model: sequelize.models.EventType, as: "type", attributes: ["name", "title"] },
      ],
      group: ["location.country", "location.city", "Event.typeId"],
      attributes: [
        "location.country",
        "location.city",
        "type.name",
        "type.title",
        [sequelize.fn("COUNT", sequelize.col("Event.typeId")), "ediciones"],
        [sequelize.fn("SUM", sequelize.col("Event.assistants")), "assistants"],
      ],
    };
  });

  Event.addScope("onlyOfLocation", (location) => {
    return {
      where: { locationId: { [Sequelize.Op.eq]: location } },
    };
  });

  return Event;
};
