import { Op } from 'sequelize';
import CalendarEvent from '../models/CalendarEvent.js';
import { checkAccess } from '../utils/userUtils.js';
import HttpError from '../exceptions/HttpError.js';

class CalendarEventService {
  async listClubEvents(userToken, clubId, year) {
    await checkAccess(userToken, clubId);
    const normalizedYear = this.normalizeYear(year);
    return await CalendarEvent.findAll({
      where: {
        clubId,
        startDate: { [Op.lte]: `${normalizedYear}-12-31` },
        endDate: { [Op.gte]: `${normalizedYear}-01-01` },
      },
      order: [['startDate', 'ASC'], ['title', 'ASC']],
    });
  }

  async createClubEvent(userToken, clubId, payload, userId = null) {
    await checkAccess(userToken, clubId);
    const normalized = this.normalizePayload(payload);
    this.validatePayload(normalized);

    return await CalendarEvent.create({
      clubId,
      ...normalized,
      organizerUserId: Number(userId || payload?.organizerUserId || 0) || null,
    });
  }

  async updateClubEvent(userToken, clubId, eventId, payload, userId = null) {
    await checkAccess(userToken, clubId);
    const event = await CalendarEvent.findOne({ where: { id: eventId, clubId } });
    if (!event) throw new HttpError('Event nicht gefunden', 404);
    const normalized = this.normalizePayload(payload);
    this.validatePayload(normalized);
    await event.update({
      ...normalized,
      organizerUserId: Number(userId || payload?.organizerUserId || event.organizerUserId || 0) || null,
    });
    return event;
  }

  async deleteClubEvent(userToken, clubId, eventId) {
    await checkAccess(userToken, clubId);
    const event = await CalendarEvent.findOne({ where: { id: eventId, clubId } });
    if (!event) throw new HttpError('Event nicht gefunden', 404);
    await event.destroy();
    return { success: true };
  }

  normalizeYear(year) {
    const parsed = Number.parseInt(year, 10);
    if (Number.isInteger(parsed) && parsed >= 2020 && parsed <= 2100) return parsed;
    return new Date().getFullYear();
  }

  normalizeDate(date) {
    const text = String(date || '').slice(0, 10);
    return /^\d{4}-\d{2}-\d{2}$/.test(text) ? text : null;
  }

  normalizePayload(payload = {}) {
    return {
      title: String(payload?.title || '').trim().slice(0, 255),
      eventType: ['club_event', 'meeting', 'tournament', 'social', 'workshop', 'other'].includes(payload?.eventType)
        ? payload.eventType
        : 'club_event',
      status: ['planning', 'invited', 'confirmed', 'done', 'cancelled'].includes(payload?.status)
        ? payload.status
        : 'planning',
      description: payload?.description ? String(payload.description).trim() : null,
      location: payload?.location ? String(payload.location).trim().slice(0, 255) : null,
      startDate: this.normalizeDate(payload?.startDate),
      endDate: this.normalizeDate(payload?.endDate || payload?.startDate),
      registrationDeadline: this.normalizeDate(payload?.registrationDeadline),
      category: payload?.category ? String(payload.category).trim().slice(0, 64) : null,
      notes: payload?.notes ? String(payload.notes).trim() : null,
    };
  }

  validatePayload(payload) {
    if (!payload.title) throw new HttpError('Titel fehlt', 400);
    if (!payload.startDate || !payload.endDate) throw new HttpError('Ungültiges Datum', 400);
    if (payload.startDate > payload.endDate) throw new HttpError('Enddatum darf nicht vor dem Startdatum liegen', 400);
    if (payload.registrationDeadline && payload.registrationDeadline > payload.startDate) {
      throw new HttpError('Anmeldefrist darf nicht nach dem Startdatum liegen', 400);
    }
  }
}

export default new CalendarEventService();
