// src/serialization/toTopics.ts
// Serialize Matrix component to Topics representation
//
// Topics representation shows the pub/sub structure of a component.
//
// Reference: Vision/14-HOMOICONIC-ARCHITECTURE.md (Pillars 15-16: SERIALIZE/EVAL)

import type { IComponentSchema } from './IComponentSchema';
import type { ISerializationOptions } from './ISerializationOptions';

/**
 * Convert component schema to Topics representation
 *
 * @example
 * toTopics({ name: 'Button', mount: 'app.btn', accepts: { click: {} }, emits: { clicked: {} } })
 * // Returns:
 * // # Topics for Button
 * //
 * // ## Accepts (subscribes to)
 * // app.btn.accepts.click
 * //
 * // ## Emits (publishes to)
 * // app.btn.emits.clicked
 */
export function toTopics(
  schema: IComponentSchema,
  options: ISerializationOptions = {}
): string {
  const { pretty = true, includeComments = true } = options;
  const lines: string[] = [];

  const mount = schema.mount || `component.${toKebabCase(schema.name)}`;

  if (includeComments) {
    lines.push(`# Topics for ${schema.name}`);
    lines.push('');
  }

  // Accepts topics
  if (Object.keys(schema.accepts).length > 0) {
    if (includeComments) {
      lines.push('## Accepts (subscribes to)');
    }
    for (const [name, method] of Object.entries(schema.accepts)) {
      const topic = `${mount}.accepts.${name}`;
      if (includeComments && method.description) {
        lines.push(`# ${method.description}`);
      }
      lines.push(topic);
    }
    lines.push('');
  }

  // Emits topics
  if (Object.keys(schema.emits).length > 0) {
    if (includeComments) {
      lines.push('## Emits (publishes to)');
    }
    for (const [name, event] of Object.entries(schema.emits)) {
      const topic = `${mount}.emits.${name}`;
      if (includeComments && event.description) {
        lines.push(`# ${event.description}`);
      }
      lines.push(topic);
    }
    lines.push('');
  }

  // Lifecycle topics
  if (includeComments) {
    lines.push('## Lifecycle');
    lines.push(`${mount}.lifecycle.available`);
    lines.push(`${mount}.lifecycle.removed`);
    lines.push('');
  }

  // Children
  if (schema.children && schema.children.length > 0) {
    if (includeComments) {
      lines.push('## Children');
    }
    for (const child of schema.children) {
      const childTopics = toTopics(child, { ...options, includeComments: false });
      lines.push(childTopics);
    }
  }

  return pretty ? lines.join('\n') : lines.filter(l => !l.startsWith('#')).join('\n');
}

/**
 * Get all topics for a component as an array
 */
export function getTopicsArray(schema: IComponentSchema): string[] {
  const topics: string[] = [];
  const mount = schema.mount || `component.${toKebabCase(schema.name)}`;

  // Accepts topics
  for (const name of Object.keys(schema.accepts)) {
    topics.push(`${mount}.accepts.${name}`);
  }

  // Emits topics
  for (const name of Object.keys(schema.emits)) {
    topics.push(`${mount}.emits.${name}`);
  }

  // Lifecycle topics
  topics.push(`${mount}.lifecycle.available`);
  topics.push(`${mount}.lifecycle.removed`);

  // Children
  if (schema.children) {
    for (const child of schema.children) {
      topics.push(...getTopicsArray(child));
    }
  }

  return topics;
}

/**
 * Generate topic subscription map
 */
export function getSubscriptionMap(schema: IComponentSchema): Record<string, string> {
  const map: Record<string, string> = {};
  const mount = schema.mount || `component.${toKebabCase(schema.name)}`;

  for (const name of Object.keys(schema.accepts)) {
    map[`${mount}.accepts.${name}`] = `on${capitalize(name)}`;
  }

  return map;
}

/**
 * Generate topic publication map
 */
export function getPublicationMap(schema: IComponentSchema): Record<string, string> {
  const map: Record<string, string> = {};
  const mount = schema.mount || `component.${toKebabCase(schema.name)}`;

  for (const name of Object.keys(schema.emits)) {
    map[name] = `${mount}.emits.${name}`;
  }

  return map;
}

/**
 * Convert to kebab-case
 */
function toKebabCase(str: string): string {
  return str
    .replace(/([a-z])([A-Z])/g, '$1-$2')
    .replace(/[\s_]+/g, '-')
    .toLowerCase();
}

/**
 * Capitalize first letter
 */
function capitalize(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
