// src/serialization/Serializable.ts
// Abstract base class for serializable components
//
// This file is separate from ISerializable.ts to avoid circular dependencies.
// The class imports converters, while converters only import types.
//
// Reference: Vision/14-HOMOICONIC-ARCHITECTURE.md (Pillars 15-16: SERIALIZE/EVAL)

import type { ISerializable } from './ISerializable';
import type { SerializationFormat } from './SerializationFormat';
import type { IComponentSchema } from './IComponentSchema';

// Import converters - NO circular dependency because converters import from types.ts
import { toHtml } from './toHtml';
import { toFluent } from './toFluent';
import { toSExpr } from './toSExpr';
import { toTopics } from './toTopics';

/**
 * Abstract base class for serializable components
 *
 * Extend this class and implement toSchema() to get automatic
 * serialization to all 5 representation formats.
 *
 * @example
 * class MyComponent extends Serializable {
 *   toSchema(): IComponentSchema {
 *     return {
 *       name: 'MyComponent',
 *       accepts: { doThing: { params: {} } },
 *       emits: { thingDone: { payload: {} } }
 *     };
 *   }
 * }
 *
 * const comp = new MyComponent();
 * comp.serialize('html');   // → <matrix-my-component>...</matrix-my-component>
 * comp.serialize('sexpr');  // → (component "MyComponent" ...)
 */
export abstract class Serializable implements ISerializable {
  /**
   * Get the canonical schema for this component.
   * Subclasses must implement this.
   */
  abstract toSchema(): IComponentSchema;

  /**
   * Serialize to the specified format.
   *
   * @param format - One of: 'html', 'fluent', 'sexpr', 'topics', 'json'
   * @returns Serialized string representation
   */
  serialize(format: SerializationFormat): string {
    const schema = this.toSchema();

    switch (format) {
      case 'html':
        return toHtml(schema);
      case 'fluent':
        return toFluent(schema);
      case 'sexpr':
        return toSExpr(schema);
      case 'topics':
        return toTopics(schema);
      case 'json':
        return JSON.stringify(schema, null, 2);
      default:
        throw new Error(`Unknown format: ${format}`);
    }
  }
}
