const { Event, Institution, EventPlace, ContactPerson, EventType, EventContactPerson, sequelize } = require('../models');
const { Op, fn, col, where: sequelizeWhere } = require('sequelize');

function buildUpcomingWhere() {
  return {
    [Op.or]: [
      { date: { [Op.eq]: null } },
      // Fixed-date events: only today or future (date-only compare).
      sequelizeWhere(fn('DATE', col('date')), { [Op.gte]: fn('CURDATE') }),
    ],
  };
}

const getAllEvents = async (req, res) => {
  try {
    const includePast = String(req.query?.includePast || '').toLowerCase();
    const wantsPast = includePast === '1' || includePast === 'true' || includePast === 'yes';

    const where = wantsPast
      ? undefined
      : buildUpcomingWhere();

    const events = await Event.findAll({
      where,
      include: [
        { model: Institution, as: 'institution' },
        { model: EventPlace, as: 'eventPlace' },
        { model: EventType, as: 'eventType' },
        { model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
      ],
      order: [
        ['date', 'ASC'],
        ['time', 'ASC'],
        ['name', 'ASC'],
      ],
    });
    res.json(events);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch events' });
    console.error(error);
  }
};

const filterEvents = async (req, res) => {
  try {
    const request = req.body;
    const where = buildUpcomingWhere();
    const order = [
      ['date', 'ASC'],
      ['time', 'ASC']
    ];

    if (request.id === 'all') {
      const events = await Event.findAll({
        where,
        include: [
          { model: Institution, as: 'institution' },
          { model: EventPlace, as: 'eventPlace' },
          { model: EventType, as: 'eventType' },
          { model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
        ],
        order: order,
        logging: console.log  // Log the generated SQL query
      });
      return res.json({ events });
    }

    if (request.id === 'home') {
      const events = await Event.findAll({
        where: {
          alsoOnHomepage: 1,
          ...buildUpcomingWhere(),
        },
        include: [
          { model: Institution, as: 'institution' },
          { model: EventPlace, as: 'eventPlace' },
          { model: EventType, as: 'eventType' },
          { model: ContactPerson, as: 'contactPersons', through: { attributes: [] } },
        ],
        order: order,
      });
      return res.json({ events });
    }

    if (!request.id && !request.places && !request.types) {
      return res.json({ events: [], places: [], types: [], contactPersons: [] });
    }

    if (request.id) {
      where.id = request.id;
    }

    if (request.places && request.places.length > 0) {
      where.event_place_id = {
        [Op.in]: request.places.map(id => parseInt(id))
      };
    }

    if (request.types && request.types.length > 0) {
      where.eventTypeId = {
        [Op.in]: request.types.map(id => parseInt(id))
      };
    }

    const events = await Event.findAll({
      where,
      include: [
        { model: Institution, as: 'institution' },
        { model: EventPlace, as: 'eventPlace' },
        { model: EventType, as: 'eventType' },
        { model: ContactPerson, as: 'contactPersons', through: { attributes: [] } }
      ],
      order: order,
    });
    const displayFields = request.display ? request.display : [];

    const filteredEvents = events.map(event => {
      const filteredEvent = { ...event.toJSON() };

      if (!displayFields.includes('name')) delete filteredEvent.name;
      if (!displayFields.includes('type')) delete filteredEvent.eventType;
      if (!displayFields.includes('place')) delete filteredEvent.eventPlace;
      if (!displayFields.includes('description')) delete filteredEvent.description;
      if (!displayFields.includes('time')) delete filteredEvent.time;
      if (!displayFields.includes('time')) delete filteredEvent.endTime;
      if (!displayFields.includes('contactPerson')) delete filteredEvent.contactPersons;
      if (!displayFields.includes('day')) delete filteredEvent.dayOfWeek;
      if (!displayFields.includes('institution')) delete filteredEvent.institution;

      return filteredEvent;
    });

    res.json({ events: filteredEvents });
  } catch (error) {
    res.status(500).json({ error: 'Failed to filter events' });
    console.error(error);
  }
};

const createEvent = async (req, res) => {
  try {
    const { contactPersonIds, ...eventData } = req.body;
    eventData.alsoOnHomepage = eventData.alsoOnHomepage ?? 0;
    const event = await Event.create(eventData);
    if (contactPersonIds) {
      await event.setContactPersons(contactPersonIds);
    }
    res.status(201).json(event);
  } catch (error) {
    res.status(500).json({ error: 'Failed to create event' });
    console.error(error);
  }
};

const updateEvent = async (req, res) => {
  try {
    const { id } = req.params;
    const { contactPersonIds, ...eventData } = req.body;
    const event = await Event.findByPk(id);
    if (!event) {
      return res.status(404).json({ error: 'Event not found' });
    }
    await event.update(eventData);
    if (contactPersonIds) {
      await event.setContactPersons(contactPersonIds);
    }
    res.status(200).json(event);
  } catch (error) {
    res.status(500).json({ error: 'Failed to update event' });
    console.error(error);
  }
};

const deleteEvent = async (req, res) => {
  const transaction = await sequelize.transaction();
  try {
    const { id } = req.params;
    // Erst Zuordnungen in der Join-Tabelle löschen, damit FK-Constraints erfüllt sind.
    await EventContactPerson.destroy({
      where: { event_id: id },
      transaction,
    });

    const deleted = await Event.destroy({
      where: { id: id },
      transaction,
    });
    if (deleted) {
      await transaction.commit();
      res.status(204).json();
    } else {
      await transaction.rollback();
      res.status(404).json({ error: 'Event not found' });
    }
  } catch (error) {
    await transaction.rollback();
    res.status(500).json({ error: 'Failed to delete event' });
    console.error(error);
  }
};

module.exports = {
  getAllEvents,
  createEvent,
  updateEvent,
  deleteEvent,
  filterEvents
};
