import { Router, Request, Response } from 'express';
import { prisma } from '../db/prisma';
import { respondIfOrganizerMigrationNeeded } from '../lib/prismaMigrationHint';

const router = Router();

function escapeIcs(text: string): string {
  return text
    .replace(/\\/g, '\\\\')
    .replace(/;/g, '\\;')
    .replace(/,/g, '\\,')
    .replace(/\n/g, '\\n')
    .replace(/\r/g, '');
}

// ICS lines must be folded at 75 octets (RFC 5545 §3.1)
function fold(line: string): string {
  const MAX = 75;
  if (line.length <= MAX) return line;
  let out = '';
  let pos = 0;
  while (pos < line.length) {
    if (pos === 0) {
      out += line.slice(0, MAX);
      pos = MAX;
    } else {
      out += '\r\n ' + line.slice(pos, pos + MAX - 1);
      pos += MAX - 1;
    }
  }
  return out;
}

function toIcsDate(d: Date): string {
  const p = (n: number) => String(n).padStart(2, '0');
  return (
    `${d.getUTCFullYear()}${p(d.getUTCMonth() + 1)}${p(d.getUTCDate())}` +
    `T${p(d.getUTCHours())}${p(d.getUTCMinutes())}${p(d.getUTCSeconds())}Z`
  );
}

// Parse "HH:MM", "H:MM am/pm", "Hpm" etc.
function parseLocalTime(t: string): { h: number; m: number } {
  const clean = t.trim();
  const m24 = clean.match(/^(\d{1,2}):(\d{2})$/);
  if (m24) return { h: parseInt(m24[1]), m: parseInt(m24[2]) };

  const mAp = clean.match(/^(\d{1,2})(?::(\d{2}))?\s*(am|pm)$/i);
  if (mAp) {
    let h = parseInt(mAp[1]);
    const m = mAp[2] ? parseInt(mAp[2]) : 0;
    if (mAp[3].toLowerCase() === 'pm' && h !== 12) h += 12;
    if (mAp[3].toLowerCase() === 'am' && h === 12) h = 0;
    return { h, m };
  }
  return { h: 18, m: 0 };
}

// Brussels is UTC+1 (CET) / UTC+2 (CEST). Use +1 as conservative default.
const BRUSSELS_OFFSET_HOURS = 1;

function parseEventDates(
  dateStr: string,
  timeStr: string
): { start: Date; end: Date } {
  const [year, month, day] = dateStr.split('-').map(Number);
  const parts = timeStr.split(/\s*[-–]\s*/);
  const { h: startH, m: startM } = parseLocalTime(parts[0]);

  // Convert local Brussels time to UTC
  const utcStartH = startH - BRUSSELS_OFFSET_HOURS;
  const start = new Date(Date.UTC(year, month - 1, day, utcStartH, startM, 0));

  let end: Date;
  if (parts[1]) {
    const { h: endH, m: endM } = parseLocalTime(parts[1]);
    const utcEndH = endH - BRUSSELS_OFFSET_HOURS;
    end = new Date(Date.UTC(year, month - 1, day, utcEndH, endM, 0));
    if (end <= start) end = new Date(end.getTime() + 24 * 60 * 60 * 1000);
  } else {
    end = new Date(start.getTime() + 2 * 60 * 60 * 1000);
  }

  return { start, end };
}

router.get('/ics', async (_req: Request, res: Response) => {
  try {
    const sevenDaysAgo = new Date();
    sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
    const cutoff = sevenDaysAgo.toISOString().slice(0, 10);

    const meetups = await prisma.meetup.findMany({
      where: { date: { gte: cutoff } },
      orderBy: { date: 'asc' },
      include: { organizer: true },
    });

    const siteUrl = (process.env.FRONTEND_URL || 'https://belgianbitcoinembassy.org').replace(
      /\/$/,
      ''
    );
    const now = new Date();

    const lines: string[] = [
      'BEGIN:VCALENDAR',
      'VERSION:2.0',
      'PRODID:-//Belgian Bitcoin Embassy//Events//EN',
      'CALSCALE:GREGORIAN',
      'METHOD:PUBLISH',
      fold('X-WR-CALNAME:Belgian Bitcoin Embassy Events'),
      fold('X-WR-CALDESC:Upcoming meetups and events by the Belgian Bitcoin Embassy'),
      'X-WR-TIMEZONE:Europe/Brussels',
    ];

    for (const meetup of meetups) {
      try {
        const { start, end } = parseEventDates(meetup.date, meetup.time);
        const eventUrl = meetup.link || `${siteUrl}/events/${meetup.id}`;

        lines.push('BEGIN:VEVENT');
        lines.push(fold(`UID:${meetup.id}@belgianbitcoinembassy.org`));
        lines.push(`DTSTAMP:${toIcsDate(now)}`);
        lines.push(`DTSTART:${toIcsDate(start)}`);
        lines.push(`DTEND:${toIcsDate(end)}`);
        lines.push(fold(`SUMMARY:${escapeIcs(meetup.title)}`));
        if (meetup.description) {
          lines.push(fold(`DESCRIPTION:${escapeIcs(meetup.description)}`));
        }
        if (meetup.location) {
          lines.push(fold(`LOCATION:${escapeIcs(meetup.location)}`));
        }
        lines.push(fold(`URL:${eventUrl}`));
        const orgName = meetup.organizer?.name || 'Belgian Bitcoin Embassy';
        lines.push(
          fold(
            `ORGANIZER;CN=${escapeIcs(orgName)}:mailto:info@belgianbitcoinembassy.org`
          )
        );
        // 15-minute reminder alarm
        lines.push('BEGIN:VALARM');
        lines.push('TRIGGER:-PT15M');
        lines.push('ACTION:DISPLAY');
        lines.push(fold(`DESCRIPTION:Reminder: ${escapeIcs(meetup.title)}`));
        lines.push('END:VALARM');
        lines.push('END:VEVENT');
      } catch {
        // Skip events with unparseable dates
      }
    }

    lines.push('END:VCALENDAR');

    const icsBody = lines.join('\r\n') + '\r\n';

    res.set({
      'Content-Type': 'text/calendar; charset=utf-8',
      'Content-Disposition': 'inline; filename="bbe-events.ics"',
      'Cache-Control': 'public, max-age=300',
    });
    res.send(icsBody);
  } catch (err) {
    console.error('Calendar ICS error:', err);
    if (respondIfOrganizerMigrationNeeded(err, res)) return;
    res.status(500).json({ error: 'Internal server error' });
  }
});

export default router;
