import { Thread } from '../Thread.mjs';
import { nestedWindowToThreadTarget } from './window/ThreadNestedWindow.mjs';

/**
 * Creates a thread from within an iframe nested in a top-level document.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
 *
 * @example
 * import {ThreadNestedIframe} from '@quilted/threads';
 *
 * const thread = new ThreadNestedIframe();
 * await thread.imports.sendMessage('Hello world!');
 */
class ThreadNestedIframe extends Thread {
  /**
   * Starts a thread wrapped around a parent window, and returns the imports
   * of the thread.
   *
   * @example
   * ```ts
   * import {ThreadNestedIframe} from '@quilted/threads';
   *
   * const {getMessage} = ThreadNestedIframe.import();
   * const message = await getMessage(); // 'Hello, world!'
   *
   * // In the parent window:
   *
   * import {ThreadIframe} from '@quilted/threads';
   *
   * ThreadIframe.export(iframe, {
   *   async getMessage() {
   *     return 'Hello, world!';
   *   },
   * });
   * ```
   */
  static import(options) {
    return new ThreadNestedIframe(options).imports;
  }

  /**
   * Starts a thread wrapped around a parent window, providing the second
   * argument as the exports of the thread.
   *
   * @example
   * ```ts
   * import {ThreadNestedIframe} from '@quilted/threads';
   *
   * ThreadNestedIframe.export({
   *   async getMessage() {
   *     return 'Hello, world!';
   *   },
   * });
   *
   * // In the parent window:
   *
   * import {ThreadIframe} from '@quilted/threads';
   *
   * const {getMessage} = ThreadIframe.import(iframe);
   * const message = await getMessage(); // 'Hello, world!'
   * ```
   */
  static export(exports, options) {
    new ThreadNestedIframe({
      ...options,
      exports
    });
  }
  constructor({
    parent = globalThis.parent,
    targetOrigin = '*',
    ...options
  } = {}) {
    if (typeof self === 'undefined' || parent == null) {
      throw new Error('You are not inside an iframe, because there is no parent window.');
    }
    super(nestedWindowToThreadTarget(parent, {
      targetOrigin
    }), options);
    this.parent = parent;
  }
}

export { ThreadNestedIframe };
