/**
 * 设计器模拟器，负责加载设计器模拟器的资源，并且提供一个模拟器的实例
 */

import { AssetsJSON, IFileSchema } from './types';
import { Renderer } from './renderer';
import { Assets } from './Assets';
import { VUE_LIBRARY_NAME } from './constants';
import { Project } from './models';
import { emitter, EVENT_ASSETS_READY } from './emitter';
export interface Env {
  global: Window;
  Vue: any;
  libs: Record<string, any>;
  components: Record<string, any>;
  container?: HTMLElement;
}

function createAssetScripts(scripts: string[]): string {
  return scripts.map((url) => `<script src="${url}"></script>`).join('');
}

function createAssetsCss(css: string[] = []) {
  return css.map((url) => `<link rel="stylesheet" href="${url}" />`).join('');
}

function createEnv(assets: AssetsJSON, contentWindow: Window) {
  const { packages = [] } = assets;
  const env: Env = {
    global: contentWindow,
    Vue: null,
    libs: {},
    components: {},
    container: contentWindow?.document?.body as HTMLElement
  };
  packages.forEach(({ library, components }) => {
    const lib = (contentWindow as any)[library];
    env.libs[library] = lib;
    if (library === VUE_LIBRARY_NAME) {
      env.Vue = lib;
    }
    if (components && components.length > 0) {
      components.forEach((name) => {
        env.components[name] = lib[name];
      });
    }
  });

  return env;
}

export interface SimulatorOptions {
  assets: Assets;
  renderer: any;
  project: Project;
}

export class Simulator {
  private assets: Assets;
  private renderer: Renderer;
  private contentWindow: Window | null = null;
  private env: Env = { global: window, Vue: null, libs: {}, components: {} };
  private project: Project;
  constructor(options: SimulatorOptions) {
    this.assets = options.assets;
    this.renderer = options.renderer;
    this.project = options.project;
  }

  init(iframe: HTMLIFrameElement, callback: () => void) {
    if (this.assets.isReady) {
      this.doInit(iframe);
      callback && callback();
    } else {
      emitter.on(EVENT_ASSETS_READY, () => {
        this.doInit(iframe);
        callback && callback();
      });
    }
  }

  doInit(iframe: HTMLIFrameElement) {
    this.contentWindow = iframe.contentWindow as Window;
    const { scripts, css } = this.assets.parsePackages();
    (this.contentWindow as any).__simulator__ = this;
    const doc = this.contentWindow.document;
    doc.open();
    doc.write(`
     <!DOCTYPE html>
     <html lang="zh-CN">
       <head>
       <meta charset="utf-8">
       <meta name="viewport"
             content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,viewport-fit=cover"/>
         <style>
            html, body {
              background: #fff;
              padding: 0;
              margin: 0;
              height: 100%;
              width: 100%;
            }
         </style>
         ${createAssetsCss(css)}
         ${createAssetScripts(scripts)}
       </head>
       <body> 
       </body>
       <script>
       __simulator__.render();
     </script> 
     </html>
    `);
    doc.close();
  }

  render() {
    this.env = createEnv(this.assets, this.contentWindow as Window);
    this.renderer.run(this.env, this.project);
  }

  draw(schema: IFileSchema) {
    this.renderer.draw(schema);
  }

  dispose() {
    this.renderer.stop();
    this.contentWindow = null;
  }
}
