/**
 * Event Types Generator
 *
 * Generates typed event payload interfaces from spec event definitions.
 * Replaces the `any` payload types in the bus generator with real types.
 */

import type { TemplateContext } from '@specverse/types';

/** Map SpecVerse types to TypeScript types */
function tsType(specType: string): string {
  const map: Record<string, string> = {
    String: 'string', Text: 'string', Email: 'string', URL: 'string',
    Integer: 'number', Float: 'number', Number: 'number', Decimal: 'number', Money: 'number',
    Boolean: 'boolean',
    Date: 'string', DateTime: 'string', Timestamp: 'string',
    UUID: 'string',
    Object: 'Record<string, any>', Array: 'any[]',
  };
  return map[specType] || 'any';
}

export default function generateEventTypes(context: TemplateContext): string {
  const { spec } = context;
  const events = spec.events && typeof spec.events === 'object'
    ? Object.entries(spec.events) : [];

  if (events.length === 0) {
    return `/**
 * Event Types — no events defined in specification
 */
export type EventPayloads = Record<string, any>;
`;
  }

  const interfaces: string[] = [];
  const payloadMapEntries: string[] = [];

  for (const [eventName, eventDef] of events) {
    const def = eventDef as any;
    const attrs = def.attributes || def.payload || {};

    // Handle both array and object attribute formats
    const attrEntries: Array<[string, any]> = Array.isArray(attrs)
      ? attrs.map((a: any) => [a.name, a])
      : Object.entries(attrs);

    const fields = attrEntries.map(([name, attrDef]) => {
      const type = typeof attrDef === 'string'
        ? tsType(attrDef.split(' ')[0])
        : tsType(attrDef?.type || 'String');
      const required = typeof attrDef === 'string'
        ? attrDef.includes('required')
        : attrDef?.required;
      return `  ${name}${required ? '' : '?'}: ${type};`;
    });

    interfaces.push(`export interface ${eventName}Payload {
${fields.join('\n')}
}`);

    payloadMapEntries.push(`  ${eventName}: ${eventName}Payload;`);
  }

  // Also add standard CURED events for each model
  const models = spec.models ? Object.keys(spec.models) : [];
  for (const model of models) {
    for (const suffix of ['Created', 'Updated', 'Deleted', 'Evolved']) {
      const name = `${model}${suffix}`;
      if (!payloadMapEntries.some(e => e.includes(name))) {
        payloadMapEntries.push(`  ${name}: { id: string; timestamp: string; [key: string]: any };`);
      }
    }
  }

  return `/**
 * Event Payload Types
 * Generated from SpecVerse specification
 */

${interfaces.join('\n\n')}

/**
 * Map of all event names to their payload types
 */
export type EventPayloads = {
${payloadMapEntries.join('\n')}
};

/**
 * All known event names
 */
export type EventName = keyof EventPayloads;
`;
}
