// src/engine/reflection/GraphBuilder.ts

import type { IGraphSpec, IComponentSpec, IPhantomChildSpec } from './GraphSpec';

type ComponentBuilderParent = GraphBuilder | ComponentBuilder;

export class ComponentBuilder {
  private spec: IComponentSpec;
  private parent: ComponentBuilderParent;

  constructor(parent: ComponentBuilderParent, name: string, tag?: string) {
    this.parent = parent;
    this.spec = { name, tag, children: [], phantomChildren: [] };

    if (parent instanceof GraphBuilder) {
      parent._addComponent(this.spec);
    } else {
      parent._addChild(this.spec);
    }
  }

  tag(tag: string): this {
    this.spec.tag = tag;
    return this;
  }

  mountSuffix(suffix: string): this {
    this.spec.mountSuffix = suffix;
    return this;
  }

  accepts(...channels: string[]): this {
    this.spec.accepts = [...(this.spec.accepts ?? []), ...channels];
    return this;
  }

  emits(...events: string[]): this {
    this.spec.emits = [...(this.spec.emits ?? []), ...events];
    return this;
  }

  implements(ifaceName: string): this {
    this.spec.ifaceName = ifaceName;
    return this;
  }

  child(name: string, tag?: string): ComponentBuilder {
    return new ComponentBuilder(this, name, tag);
  }

  phantomChild(name: string, mount: string, tag?: string, ifaceName?: string): this {
    (this.spec.phantomChildren ??= []).push({ name, mount, tag, ifaceName });
    return this;
  }

  end(): ComponentBuilderParent {
    return this.parent;
  }

  _getSpec(): IComponentSpec {
    return this.spec;
  }

  _addChild(child: IComponentSpec): void {
    (this.spec.children ??= []).push(child);
  }
}

export class GraphBuilder {
  private components: IComponentSpec[] = [];

  constructor() {}

  component(name: string, tag?: string): ComponentBuilder {
    return new ComponentBuilder(this, name, tag);
  }

  _addComponent(spec: IComponentSpec): void {
    this.components.push(spec);
  }

  build(): IGraphSpec {
    return {
      components: this.components,
    };
  }
}
