import { json, HttpClient } from 'aurelia-fetch-client';
import { customElement, bindable, TaskQueue, inlineView, bindingMode, autoinject } from 'aurelia-framework';
import { Router } from 'aurelia-router';
import { Config } from '../../config';
import tinymce, { Editor, RawEditorOptions } from 'tinymce';
import { Guid } from './utilities/guid';

// Any plugins you want to use has to be imported

interface BlobInfo {
  id: () => string;
  name: () => string;
  filename: () => string;
  blob: () => Blob;
  base64: () => string;
  blobUri: () => string;
  uri: () => string | undefined;
}

@inlineView(`<template> 
<div>
  <div id.bind="editorId" class="tinymce-editor"></div>
</div>
</template>`)
@customElement('tiny-mce')
@autoinject
export class TinyMce {
  @bindable({ defaultBindingMode: bindingMode.oneTime })
  public theme: "silver" | "modern" | "mobile" | "inlite" = "silver";
  @bindable({ defaultBindingMode: bindingMode.oneTime })
  public inline: boolean = false;
  @bindable({ defaultBindingMode: bindingMode.twoWay })
  public content: string = '';
  @bindable
  public readonly: boolean = false;
  @bindable({ defaultBindingMode: bindingMode.oneTime })
  public options: RawEditorOptions;
  @bindable imageFolderName: string;

  public editorId = '';
  public editorInstance: Editor = null;
  isDestroying: boolean = false;

  constructor(private element: Element, private taskQueue: TaskQueue, router: Router, private config: Config, private httpClient: HttpClient) {
    this.setBaseUrl(router);
  }

  public bind() {
    this.options = Object.assign({}, this.config.defaultRichTextEditorOptions, this.options);
    this.setEditorId();
    if (this.inline !== false) this.inline = true;
  }

  public attached() {
    this.taskQueue.queueMicroTask(() => {
      let el = this.element.getElementsByClassName('tinymce-editor').item(0);
      el.removeAttribute('style');
      el.removeAttribute('aria-hidden');

      this.options.target = el as HTMLElement;
      this.options.theme = this.theme;
      (this.options as any).mobile = {
        theme: this.theme
      };
      (this.options as any).readonly = this.readonly;
      this.options.inline = this.inline;
      this.options.images_upload_handler = (blobInfo) => this.images_upload_handler(blobInfo);

      let save_init_instance_callback = this.options.init_instance_callback; //we save it because it will be erased on the following line.
      this.options.init_instance_callback = (editor: Editor) => {
        editor.on('Change KeyUp', (e) => {
          if (this.isDestroying === true) return;
          this.content = this.getContent();
        });
        if (save_init_instance_callback) {
          save_init_instance_callback(editor);
        }
        if (this.editorInstance && this.content) {
          this.setContent(this.content);
        }
      };
      tinymce.init(this.options);

      this.editorInstance = tinymce.get(this.options.target.id);
    });
  }

  public detached() {
    try {
      if (this.editorInstance) {
        this.isDestroying = true;
        this.editorInstance.destroy();
      }
    }
    catch (error) {
      console.log('Error when detaching tinymce', error);
    }
  }

  private setBaseUrl(router: Router) {
    if (router?.options?.root != null) {
      if ((router.options.root as string).startsWith('/')) {
        tinymce.baseURL = router.options.root + 'tinymce';
      }
      else {
        tinymce.baseURL = '/' + router.options.root + 'tinymce';
      }
    }
    else {
      tinymce.baseURL = '/tinymce';
    }
  }

  public setEditorId() {
    this.taskQueue.queueMicroTask(() => {
      let guid: Guid = Guid.newGuid();
      this.editorId = `editor-${guid.toString()}`;
    });
    this.taskQueue.flushMicroTaskQueue();
  }

  public contentChanged(value: string) {
    if (value !== this.getContent()) this.setContent(value);
  }

  public setContent(value: string) {
    if (this.editorInstance) {
      if (value == null) value = '';

      var el = document.createElement('html');
      el.innerHTML = value;

      var body = el.getElementsByTagName('body');
      let bodyHtml = body.item(0).innerHTML;
      this.editorInstance.setContent(bodyHtml);
    }
  }

  public getContent(): string {
    if (this.editorInstance) {
      let innerContent = this.editorInstance.getContent();
      if (innerContent == null || innerContent.length == 0) return null;
      return $('#' + this.editorId).next().find('iframe').contents().find("html").html();

    }
  }

  public readonlyChanged(readonly: boolean) {
    if (this.editorInstance) {
      if (readonly) {
        this.editorInstance.mode.set("readonly");
      }
      else {
        this.editorInstance.mode.set("design");
      }
    }
  }

  public images_upload_handler = (blobInfo: BlobInfo) => new Promise<string>(async (resolve, reject) => {
    let folderName = this.imageFolderName ?? `tiny-mce/${this.editorId}`;

    let result = await this.httpClient.post(this.config.globalConfig.remoteServiceName + this.config.globalConfig.remoteTinyMceController + `uploadBase64?folderName=${folderName}&fileName=${blobInfo.filename()}`, json(blobInfo.base64()));
    if (result.ok) {
      let uri = await result.json();
      return resolve(uri);
    } else {
      return reject("failed to upload to image");
    }
  });
}