import { z } from 'zod';
import type { AnyToolDef, ToolDef, CompositeToolDef, ToolPack } from '../../tool-registry.js';
import type { ApiClient } from '../../api-client.js';

// ---------- Standard CRUD Tools ----------

const eventTools: ToolDef[] = [
  // --- Admin Event Management ---
  {
    name: 'events_list',
    description:
      'List ticketed events. Filter by status (DRAFT, PENDING_APPROVAL, PUBLISHED, CANCELLED, COMPLETED) ' +
      'or search by title. Returns paginated results with tier counts and ticket stats.',
    inputSchema: {
      page: z.coerce.number().int().positive().default(1).describe('Page number'),
      limit: z.coerce.number().int().positive().max(100).default(20).describe('Items per page'),
      status: z.enum(['DRAFT', 'PENDING_APPROVAL', 'PUBLISHED', 'CANCELLED', 'COMPLETED']).optional()
        .describe('Filter by event status'),
      search: z.string().optional().describe('Search events by title'),
    },
    method: 'GET',
    path: '/api/ticketed-events/admin',
    tier: 2,
  },
  {
    name: 'events_get',
    description:
      'Get full details of a ticketed event by ID, including ticket tiers, ' +
      'venue info, visibility settings, and Gancio sync status.',
    inputSchema: {
      id: z.string().describe('Event ID'),
    },
    method: 'GET',
    path: '/api/ticketed-events/admin/:id',
    tier: 2,
  },
  {
    name: 'events_create',
    description:
      'Create a new ticketed event. Starts in DRAFT status. Include date (YYYY-MM-DD), ' +
      'startTime/endTime (HH:MM), venue info, and optionally initial ticket tiers. ' +
      'Set visibility to PUBLIC, UNLISTED, or PRIVATE.',
    inputSchema: {
      title: z.string().min(1).max(200).describe('Event title'),
      description: z.string().max(2000).optional().describe('Event description'),
      date: z.string().describe('Event date (YYYY-MM-DD)'),
      startTime: z.string().describe('Start time (HH:MM)'),
      endTime: z.string().describe('End time (HH:MM)'),
      doorsOpenTime: z.string().optional().describe('Doors open time (HH:MM)'),
      eventFormat: z.enum(['IN_PERSON', 'ONLINE', 'HYBRID']).optional().describe('Event format (default: IN_PERSON). ONLINE/HYBRID auto-create a Jitsi meeting room.'),
      venueName: z.string().max(200).optional().describe('Venue name'),
      venueAddress: z.string().max(500).optional().describe('Venue address'),
      visibility: z.enum(['PUBLIC', 'UNLISTED', 'PRIVATE']).optional().describe('Event visibility (default: PUBLIC)'),
      maxAttendees: z.number().int().positive().optional().describe('Maximum total attendees'),
      organizerName: z.string().max(200).optional().describe('Organizer display name'),
      organizerEmail: z.string().email().optional().describe('Organizer contact email'),
    },
    method: 'POST',
    path: '/api/ticketed-events/admin',
    tier: 2,
  },
  {
    name: 'events_update',
    description:
      'Update a ticketed event. Only provided fields are changed. ' +
      'Cannot change status directly — use events_publish, events_cancel, or events_complete.',
    inputSchema: {
      id: z.string().describe('Event ID'),
      title: z.string().min(1).max(200).optional().describe('Event title'),
      description: z.string().max(2000).optional().describe('Event description'),
      date: z.string().optional().describe('Event date (YYYY-MM-DD)'),
      startTime: z.string().optional().describe('Start time (HH:MM)'),
      endTime: z.string().optional().describe('End time (HH:MM)'),
      doorsOpenTime: z.string().optional().describe('Doors open time (HH:MM)'),
      eventFormat: z.enum(['IN_PERSON', 'ONLINE', 'HYBRID']).optional().describe('Event format. Changing to ONLINE/HYBRID auto-creates a Jitsi room.'),
      venueName: z.string().max(200).optional().describe('Venue name'),
      venueAddress: z.string().max(500).optional().describe('Venue address'),
      visibility: z.enum(['PUBLIC', 'UNLISTED', 'PRIVATE']).optional().describe('Event visibility'),
      maxAttendees: z.number().int().positive().optional().describe('Maximum total attendees'),
    },
    method: 'PUT',
    path: '/api/ticketed-events/admin/:id',
    tier: 2,
  },
  {
    name: 'events_delete',
    description:
      'Delete a ticketed event. Only DRAFT events can be deleted. ' +
      'Published or completed events must be cancelled instead.',
    inputSchema: {
      id: z.string().describe('Event ID'),
    },
    method: 'DELETE',
    path: '/api/ticketed-events/admin/:id',
    tier: 2,
  },

  // --- Event Status Transitions ---
  {
    name: 'events_publish',
    description:
      'Publish a DRAFT event, making it visible to the public. ' +
      'Requires at least one active ticket tier. Also syncs to Gancio community calendar.',
    inputSchema: {
      id: z.string().describe('Event ID'),
    },
    method: 'POST',
    path: '/api/ticketed-events/admin/:id/publish',
    tier: 2,
  },
  {
    name: 'events_cancel',
    description:
      'Cancel a published event. All VALID tickets are cancelled. ' +
      'Removed from public listings and community calendar.',
    inputSchema: {
      id: z.string().describe('Event ID'),
    },
    method: 'POST',
    path: '/api/ticketed-events/admin/:id/cancel',
    tier: 2,
  },
  {
    name: 'events_complete',
    description:
      'Mark a published event as completed (e.g., after the event date has passed).',
    inputSchema: {
      id: z.string().describe('Event ID'),
    },
    method: 'POST',
    path: '/api/ticketed-events/admin/:id/complete',
    tier: 2,
  },

  // --- Ticket Tier Management ---
  {
    name: 'events_add_tier',
    description:
      'Add a ticket tier to an event. Types: FREE (no charge), PAID (fixed price in cents CAD), ' +
      'DONATION (minimum donation amount). Set maxQuantity for limited availability.',
    inputSchema: {
      id: z.string().describe('Event ID'),
      name: z.string().min(1).max(100).describe('Tier name (e.g., "General Admission", "VIP")'),
      tierType: z.enum(['PAID', 'FREE', 'DONATION']).describe('Ticket type'),
      priceCAD: z.number().int().min(0).default(0).describe('Price in cents CAD (e.g., 2500 = $25.00)'),
      maxQuantity: z.number().int().positive().optional().describe('Maximum tickets for this tier'),
      maxPerOrder: z.number().int().min(1).max(100).default(10).describe('Max tickets per order'),
      description: z.string().max(500).optional().describe('Tier description'),
      sortOrder: z.number().int().default(0).describe('Display order (lower = first)'),
    },
    method: 'POST',
    path: '/api/ticketed-events/admin/:id/tiers',
    tier: 2,
  },
  {
    name: 'events_update_tier',
    description: 'Update a ticket tier. Only provided fields are changed.',
    inputSchema: {
      id: z.string().describe('Event ID'),
      tierId: z.string().describe('Tier ID'),
      name: z.string().min(1).max(100).optional().describe('Tier name'),
      tierType: z.enum(['PAID', 'FREE', 'DONATION']).optional().describe('Ticket type'),
      priceCAD: z.number().int().min(0).optional().describe('Price in cents CAD'),
      maxQuantity: z.number().int().positive().optional().describe('Maximum tickets'),
      maxPerOrder: z.number().int().min(1).max(100).optional().describe('Max per order'),
      isActive: z.boolean().optional().describe('Enable or disable this tier'),
    },
    method: 'PUT',
    path: '/api/ticketed-events/admin/:id/tiers/:tierId',
    tier: 2,
  },
  {
    name: 'events_delete_tier',
    description: 'Remove a ticket tier. Only possible if no tickets have been sold for this tier.',
    inputSchema: {
      id: z.string().describe('Event ID'),
      tierId: z.string().describe('Tier ID'),
    },
    method: 'DELETE',
    path: '/api/ticketed-events/admin/:id/tiers/:tierId',
    tier: 2,
  },

  // --- Ticket & Check-in Management ---
  {
    name: 'events_tickets',
    description:
      'List tickets sold for an event. Includes holder info, status (VALID, CHECKED_IN, CANCELLED, REFUNDED), ' +
      'tier assignment, and check-in timestamp.',
    inputSchema: {
      id: z.string().describe('Event ID'),
      page: z.coerce.number().int().positive().default(1).describe('Page number'),
      limit: z.coerce.number().int().positive().max(100).default(20).describe('Items per page'),
    },
    method: 'GET',
    path: '/api/ticketed-events/admin/:id/tickets',
    tier: 2,
  },
  {
    name: 'events_checkins',
    description:
      'Get check-in audit log for an event. Shows who was checked in, by whom, ' +
      'the method used (QR, MANUAL, CODE), and timestamps.',
    inputSchema: {
      id: z.string().describe('Event ID'),
      page: z.coerce.number().int().positive().default(1).describe('Page number'),
      limit: z.coerce.number().int().positive().max(100).default(20).describe('Items per page'),
    },
    method: 'GET',
    path: '/api/ticketed-events/admin/:id/checkins',
    tier: 2,
  },
  {
    name: 'events_cancel_ticket',
    description: 'Cancel a specific ticket. Decrements sold count and frees capacity.',
    inputSchema: {
      id: z.string().describe('Event ID'),
      ticketId: z.string().describe('Ticket ID'),
    },
    method: 'POST',
    path: '/api/ticketed-events/admin/:id/tickets/:ticketId/cancel',
    tier: 2,
  },

  // --- Meeting ---
  {
    name: 'events_meeting_token',
    description:
      'Generate a moderator JWT token for joining an event\'s Jitsi meeting room. ' +
      'Returns the token and a ready-to-use Jitsi URL. Only works for ONLINE/HYBRID events.',
    inputSchema: {
      id: z.string().describe('Event ID'),
    },
    method: 'POST',
    path: '/api/ticketed-events/admin/:id/meeting-token',
    tier: 2,
  },
];

// ---------- Composite Tool: Event Stats ----------

async function eventStatsHandler(args: Record<string, unknown>, api: ApiClient): Promise<string> {
  const id = args.id as string;
  if (!id) throw new Error('Event ID is required');

  const [event, stats, availability] = await Promise.allSettled([
    api.request('GET', `/api/ticketed-events/admin/${id}`),
    api.request('GET', `/api/ticketed-events/admin/${id}/stats`),
    api.request('GET', `/api/ticketed-events/${(await api.request('GET', `/api/ticketed-events/admin/${id}`) as any).slug}/availability`),
  ]);

  const sections: string[] = [];

  if (event.status === 'fulfilled') {
    const e = event.value as any;
    sections.push(
      `## Event: ${e.title}\n` +
      `- **Status:** ${e.status}\n` +
      `- **Date:** ${e.date?.split('T')[0]} ${e.startTime}–${e.endTime}\n` +
      `- **Venue:** ${e.venueName || 'TBD'}\n` +
      `- **Visibility:** ${e.visibility}\n` +
      `- **Capacity:** ${e.currentAttendees}/${e.maxAttendees || '∞'}\n`
    );
  }

  if (stats.status === 'fulfilled') {
    sections.push('## Ticket Stats\n' + JSON.stringify(stats.value, null, 2));
  }

  if (availability.status === 'fulfilled') {
    sections.push('## Tier Availability\n' + JSON.stringify(availability.value, null, 2));
  }

  return sections.join('\n\n');
}

const eventStats: CompositeToolDef = {
  name: 'events_stats',
  description:
    'Get comprehensive event statistics: ticket sales, revenue, check-in counts, ' +
    'per-tier availability, and capacity info. Combines event detail, stats, and availability.',
  inputSchema: {
    id: z.string().describe('Event ID'),
  },
  handler: eventStatsHandler,
  tier: 3,
};

// ---------- Pack Export ----------

export const eventsPack: ToolPack = {
  name: 'events',
  description: 'Ticketed events management: create events, manage ticket tiers, track sales and check-ins',
  tools: [...eventTools, eventStats],
};
