/* ---------------------------------------------------------------------------
 * Events resource.
 *
 * Slug auto-generates from title on create when blank; on edit it's a regular
 * editable text field (changing it breaks any external links — admin's call).
 * ------------------------------------------------------------------------- */

import {
  createEvent,
  updateEvent,
  deleteEvent,
  getEventById,
  getEventBySlug,
  getAllEvents,
  getEventRsvpCount,
  type Event,
  type EventKind,
} from '../../lib/db';
import { eventKindLabel } from '../../lib/format';
import { fmtDateTime } from '../../lib/markdown';
import type { Resource } from '../resource-types';

function slugify(s: string): string {
  return s
    .toLowerCase()
    .normalize('NFKD').replace(/[̀-ͯ]/g, '')
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

function uniqueEventSlug(base: string): string {
  let slug = base || 'event';
  let n = 1;
  while (getEventBySlug(slug)) {
    n += 1;
    slug = `${base}-${n}`;
  }
  return slug;
}

function toSqliteDatetime(s: string): string {
  if (!s) return '';
  return s.replace('T', ' ') + (s.length === 16 ? ':00' : '');
}

/** Compute a human duration label from start + end SQLite datetimes.
 *  Returns null when ends_at is missing (open-ended event). */
function computeDurationLabel(startsAt: string, endsAt: string | null): string | null {
  if (!endsAt) return null;
  const start = new Date(startsAt.replace(' ', 'T') + 'Z').getTime();
  const end   = new Date(endsAt.replace(' ', 'T') + 'Z').getTime();
  const ms = end - start;
  if (!Number.isFinite(ms) || ms <= 0) return null;

  const minutes = Math.round(ms / 60_000);
  if (minutes < 90) return `${minutes} min`;

  const hours = ms / 3_600_000;
  if (hours < 4) {
    const rounded = Math.round(hours * 2) / 2; // nearest half hour
    return Number.isInteger(rounded) ? `${rounded} hr` : `${rounded} hr`;
  }
  if (hours < 7)  return 'Half day';
  if (hours < 10) return 'Full day';

  const days = Math.round(hours / 24);
  return days === 1 ? '1 day' : `${days} days`;
}

export const eventsResource: Resource<Event> = {
  key: 'events',
  label: 'Events',
  pluralLabel: 'Events',
  singularLabel: 'Event',
  groupKey: 'publishing',
  description: 'Gatherings, dinners, virtual sessions — anything that shows up at /events.',
  publicRoutePattern: (item) => `/events/${item.slug}`,

  list: {
    queryFn: () => getAllEvents(),
    columns: [
      {
        key: 'title',
        label: 'Title',
        primary: true,
        width: '2fr',
        render: (item) => ({
          title: item.title,
          subtitle: item.location,
        }),
      },
      {
        key: 'kind',
        label: 'Kind',
        kind: 'pill',
        width: '140px',
        pillVariants: {
          dinner: { label: 'Dinner', class: 'pill-decision' },
          office_hours: { label: 'Studio hours', class: 'pill-update' },
          summit: { label: 'Summit', class: 'pill-note' },
          virtual: { label: 'Virtual', class: 'pill-bts' },
          working_session: { label: 'Working session', class: 'pill-considering' },
        },
      },
      {
        key: 'starts_at',
        label: 'Date',
        width: '180px',
        render: (item) => ({
          title: item.starts_at ? fmtDateTime(item.starts_at) : '—',
        }),
      },
      {
        key: 'capacity',
        label: 'Capacity',
        kind: 'number',
        width: '90px',
      },
    ],
    filters: [
      {
        key: 'all',
        label: 'All',
        predicate: () => true,
        isDefault: true,
      },
      {
        key: 'upcoming',
        label: 'Upcoming',
        predicate: (i) => new Date(i.starts_at).getTime() >= Date.now(),
      },
      {
        key: 'past',
        label: 'Past',
        predicate: (i) => new Date(i.starts_at).getTime() < Date.now(),
      },
    ],
    search: {
      placeholder: 'Search by title or location…',
      fields: ['title', 'location', 'description'],
    },
    defaultSort: { key: 'starts_at', direction: 'desc' },
    pageSize: 25,
  },

  form: {
    fields: [
      { key: 'title', label: 'Title', kind: 'text', required: true, maxLength: 200 },
      {
        key: 'slug',
        label: 'Slug',
        kind: 'text',
        maxLength: 80,
        helperText: 'URL path under /events/. Leave blank on create to auto-generate from the title.',
      },
      {
        key: 'kind',
        label: 'Kind',
        kind: 'select',
        required: true,
        options: (['dinner', 'office_hours', 'summit', 'virtual', 'working_session'] as EventKind[]).map(
          (k) => ({ value: k, label: eventKindLabel(k) }),
        ),
        defaultValue: 'dinner',
      },
      {
        key: 'description',
        label: 'Description',
        kind: 'textarea',
        rows: 5,
        required: true,
      },
      {
        key: 'location',
        label: 'Location',
        kind: 'text',
        required: true,
        maxLength: 200,
        helperText: 'Address, room, or video link.',
      },
      { key: 'starts_at', label: 'Starts at', kind: 'datetime', required: true },
      { key: 'ends_at', label: 'Ends at', kind: 'datetime' },
      {
        key: 'capacity',
        label: 'Capacity',
        kind: 'number',
        min: 0,
        max: 999,
        helperText: 'Leave blank for uncapped.',
      },
      {
        key: 'audience',
        label: 'Audience',
        kind: 'text',
        maxLength: 200,
        helperText: 'Free-form note about who the event is for (e.g. "Council members only").',
      },
      {
        key: 'action_label',
        label: 'Action button label',
        kind: 'text',
        maxLength: 40,
        helperText: 'Override the default per-kind CTA (e.g. "Reserve your table").',
      },
      {
        key: 'photo_url',
        label: 'Photo URL',
        kind: 'text',
        maxLength: 400,
        helperText: 'Optional hero image for the event detail page.',
      },
      {
        key: 'notes_url',
        label: 'Notes URL',
        kind: 'text',
        maxLength: 400,
        helperText: 'Optional link to event notes published after the gathering.',
      },
    ],
  },

  ops: {
    getById: (id) => getEventById(id),

    create: (data, ctx) => {
      const rawSlug = ((data.slug as string) ?? '').trim();
      const slug = uniqueEventSlug(rawSlug ? slugify(rawSlug) : slugify(String(data.title)));
      const startsAt = toSqliteDatetime(String(data.starts_at));
      const endsAt = data.ends_at ? toSqliteDatetime(String(data.ends_at)) : null;
      return createEvent({
        slug,
        title: String(data.title),
        kind: data.kind as EventKind,
        description: String(data.description),
        location: String(data.location),
        starts_at: startsAt,
        ends_at: endsAt,
        capacity: data.capacity == null || data.capacity === '' ? null : Number(data.capacity),
        photo_url: ((data.photo_url as string) ?? '').trim() || null,
        audience: ((data.audience as string) ?? '').trim() || null,
        duration_label: computeDurationLabel(startsAt, endsAt),
        action_label: ((data.action_label as string) ?? '').trim() || null,
        notes_url: ((data.notes_url as string) ?? '').trim() || null,
        created_by: ctx.user.id,
      });
    },

    update: (id, data) => {
      const startsAt = toSqliteDatetime(String(data.starts_at));
      const endsAt = data.ends_at ? toSqliteDatetime(String(data.ends_at)) : null;
      updateEvent(id, {
        title: String(data.title),
        kind: data.kind as EventKind,
        description: String(data.description),
        location: String(data.location),
        starts_at: startsAt,
        ends_at: endsAt,
        capacity: data.capacity == null || data.capacity === '' ? null : Number(data.capacity),
        photo_url: ((data.photo_url as string) ?? '').trim() || null,
        audience: ((data.audience as string) ?? '').trim() || null,
        duration_label: computeDurationLabel(startsAt, endsAt),
        action_label: ((data.action_label as string) ?? '').trim() || null,
        notes_url: ((data.notes_url as string) ?? '').trim() || null,
      });
    },

    delete: (id) => deleteEvent(id),
  },
};

// Internal use, not exported on the resource — used by future row subtitles
// if we want RSVP counts in the list view. Left here as a marker.
export { getEventRsvpCount };
