// src/runtime/HeadlessHost.ts

import type { IRuntimeHost } from './IRuntimeHost';
import type { IHostDocument } from './IHostDocument';
import type { IHostCustomElementRegistry } from './IHostCustomElementRegistry';

/**
 * Runtime host for server/headless environments.
 * Uses JSDOM/similar if available, falls back to basic object mocks.
 */
export class HeadlessHost implements IRuntimeHost {
  readonly document: IHostDocument;
  readonly customElements: IHostCustomElementRegistry;

  private readonly domAvailable: boolean;
  private disposed = false;

  constructor() {
    // Check if we're in a browser-like environment
    this.domAvailable = typeof document !== 'undefined' &&
                        typeof customElements !== 'undefined';

    if (this.domAvailable) {
      this.document = document as unknown as IHostDocument;
      this.customElements = customElements as unknown as IHostCustomElementRegistry;
    } else {
      // Minimal mocks for headless environment
      this.document = createMockDocument();
      this.customElements = createMockRegistry();
    }
  }

  createElement(tagName: string): Element {
    return this.document.createElement(tagName);
  }

  dispose(): void {
    if (this.disposed) return;
    this.disposed = true;
    // Nothing else to clean up in headless mode
  }
}

function createMockDocument(): IHostDocument {
  const bodyEl = {
    tagName: 'BODY',
    children: [] as unknown[],
    appendChild(node: unknown) {
      this.children.push(node);
      return node;
    },
    removeChild(node: unknown) {
      const idx = this.children.indexOf(node);
      if (idx >= 0) this.children.splice(idx, 1);
      return node;
    }
  };

  return {
    createElement(tagName: string): Element {
      return {
        tagName: tagName.toUpperCase(),
        getAttribute(name: string) { return null; },
        setAttribute(name: string, value: string) {},
        appendChild(node: Node) { return node; },
        removeChild(node: Node) { return node; },
        parentElement: null,
        innerHTML: ''
      } as unknown as Element;
    },
    createDocumentFragment(): DocumentFragment {
      return {
        appendChild(node: Node) { return node; },
        childNodes: []
      } as unknown as DocumentFragment;
    },
    body: bodyEl as unknown as Element
  };
}

function createMockRegistry(): IHostCustomElementRegistry {
  const registry = new Map<string, CustomElementConstructor>();
  return {
    define(tagName: string, constructor: CustomElementConstructor): void {
      if (registry.has(tagName)) {
        throw new Error(`Custom element '${tagName}' already defined`);
      }
      registry.set(tagName, constructor);
    },
    get(tagName: string): CustomElementConstructor | undefined {
      return registry.get(tagName);
    },
    whenDefined(tagName: string): Promise<void> {
      return registry.has(tagName)
        ? Promise.resolve()
        : new Promise(resolve => {
            // This is a simplified mock that just resolves immediately
            // Mock constructor satisfies CustomElementConstructor interface
            registry.set(tagName, class extends HTMLElement {} as CustomElementConstructor);
            resolve();
          });
    }
  };
}
