
/**
 * EditorJsCodeCup Block for the Editor.js.
 *
 * @author Calum Knott (calum@calumk.com)
 * @license The MIT License (MIT)
 */

/**
 * @typedef {object} EditorJsCodeCupConfig
 * @property {string} placeholder - placeholder for the empty EditorJsCodeCup
 * @property {boolean} preserveBlank - Whether or not to keep blank EditorJsCodeCups when saving editor data
 */

/**
 * @typedef {Object} EditorJsCodeCupData
 * @description Tool's input and output data format
 * @property {String} text — EditorJsCodeCup's content. Can include HTML tags: <a><b><i>
 */

import style from './codecup.css'

import codecup from '@calumk/codecup/dist/codecup.bundle.js';



class EditorJsCodeCup {
  /**
   * Default placeholder for EditorJsCodeCup Tool
   *
   * @return {string}
   * @constructor
   */
  static get DEFAULT_PLACEHOLDER() {
    return '// Hello';
  }

  static get enableLineBreaks() {
    return true;
  }

  /**
   * Render plugin`s main Element and fill it with saved data
   *
   * @param {object} params - constructor params
   * @param {EditorJsCodeCupData} params.data - previously saved data
   * @param {EditorJsCodeCupConfig} params.config - user config for Tool
   * @param {object} params.api - editor.js api
   * @param {boolean} readOnly - read only mode flag
   */
  constructor({data, config, api, readOnly}) {
    //  console.log(data)
    this.api = api;
    this.readOnly = readOnly;

    this._CSS = {
      block: this.api.styles.block,
      wrapper: 'ce-EditorJsCodeCup',
      settingsButton: this.api.styles.settingsButton,
      settingsButtonActive: this.api.styles.settingsButtonActive,
    };

    if (!this.readOnly) {
      this.onKeyUp = this.onKeyUp.bind(this);
    }

    /**
     * Placeholder for EditorJsCodeCup if it is first Block
     * @type {string}
     */
    this._placeholder = config.placeholder ? config.placeholder : EditorJsCodeCup.DEFAULT_PLACEHOLDER;

    this._preserveBlank = config.preserveBlank !== undefined ? config.preserveBlank : false;

    this._element; // used to hold the wrapper div, as a point of reference



    // let x = (x === undefined) ? your_default_value : x;
    this.data = {}
    this.data.code = (data.code === undefined) ? '// Hello World' : data.code;
    this.data.language = (data.language === undefined) ? 'plain' : data.language;
    this.data.showlinenumbers = (data.showlinenumbers === undefined) ? true : data.showlinenumbers;
    this.data.showCopyButton = (data.showCopyButton === undefined) ? true : data.showCopyButton;
    this.data.editorInstance = {}

    //  console.log(this.data)

  }

  /**
   * Check if text content is empty and set empty string to inner html.
   * We need this because some browsers (e.g. Safari) insert <br> into empty contenteditanle elements
   *
   * @param {KeyboardEvent} e - key up event
   */
  onKeyUp(e) {
    if (e.code !== 'Backspace' && e.code !== 'Delete') {
      return;
    }

    console.log(e)

    const {textContent} = this._element;

    if (textContent === '') {
      this._element.innerHTML = '';
    }
  }


  /**
   * Return Tool's view
   *
   * @returns {HTMLDivElement}
   */
  render() {

    this._element = document.createElement('div');
    this._element.classList.add('editorjs-codeCup_Wrapper')
    let editorElem = document.createElement('div');
    editorElem.classList.add('editorjs-codeCup_Editor')
    let langdisplay = document.createElement('div');
    langdisplay.classList.add('editorjs-codeCup_LangDisplay')

    langdisplay.innerHTML = this.data.language

    this._element.appendChild(editorElem)
    this._element.appendChild(langdisplay)

    // console.log(this.data.editorInstance)

    this.data.editorInstance = new codecup(editorElem, {
      language: this.data.language,
      lineNumbers : this.data.showlinenumbers,
      readonly : this.readOnly,
      copyButton : this.data.showCopyButton,
    });

    // console.log(this.data.editorInstance)


    this.data.editorInstance.onUpdate((code) => {
      // console.log("onUpdate fired")
      // console.log(code)
      let _length = code.split('\n').length
      this._debounce(this._updateEditorHeight(_length))
    });


    // this.data.editorInstance.addLanguage(this.data.language, Prism.languages[this.data.language]);
    this.data.editorInstance.updateCode(this.data.code);

    // console.log(this.data.code)
    // console.log(this.data.editorInstance.getCode())
    // console.log(this._element)

    return this._element
  }

  _updateEditorHeight(length){

    let _height = (length * 21) + 10
    if (_height < 60){ _height = 60 }

    this._element.style.height = _height + 'px';
  }


  _debounce(func, timeout = 500){
    let timer;
    return (...args) => {
      clearTimeout(timer);
      timer = setTimeout(() => { func.apply(this, args); }, timeout);
    };
  }

  renderSettings() {
    const settingsContainer = document.createElement('div');




    let languagesSelect = document.createElement("select");
    languagesSelect.classList.add("codecup-language-select")

    //sort available languages alphabetically (ignore case)
    let languages = Object.keys(Prism.languages).sort(function (a, b) {
        return a.toLowerCase().localeCompare(b.toLowerCase());
    });

    //Create and append the options
    for (var i = 0; i < languages.length; i++) {
        // Weirdly PrismJS doesnt expose a list of installed languages, or rather it does, but it is mixed with helper functions, which i have to clear here.
        if (languages[i] == "extend" || languages[i] == "insertBefore" || languages[i] == "DFS") {
          continue;
        }

        var option = document.createElement("option");
        option.value = languages[i];
        option.text = languages[i];
        if(languages[i] == this.data.language){
          option.selected="selected"
        }
        languagesSelect.appendChild(option);
    }

    languagesSelect.addEventListener('change', (event) => {
      this._updateLanguage(event.target.value)
    });

    // Disabled until codeCup supports toggle of line numbers
    const toggleButton = document.createElement('label');
    toggleButton.classList.add(this._CSS.settingsButton);
    toggleButton.classList.add('codecup-toggle-linenumbers');
    toggleButton.classList.add('ce-popover-item__title');
    toggleButton.innerHTML = '<div class="ce-popover-item__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-8 -8 40 40" width="512" height="512"><path style="stroke: none !important;fill: currentColor;" d="M13,24c-.552,0-1-.448-1-1V2.011l-5.215,6.608c-.342,.434-.972,.507-1.405,.166-.434-.342-.507-.971-.166-1.405,0,0,5.343-6.767,5.371-6.794C11.16,.012,12.016-.157,12.766,.152c.75,.311,1.234,1.036,1.234,1.848V23c0,.552-.448,1-1,1Z"/></svg></div> Show line numbers'
    if(this.data.showlinenumbers){
      toggleButton.classList.toggle(this._CSS.settingsButtonActive)
    }

    toggleButton.addEventListener('click', (e) => {
      e.preventDefault();
      e.stopPropagation();
      e.target.classList.toggle(this._CSS.settingsButtonActive)
      this._toggleLineNumbers()
    });



    settingsContainer.appendChild(languagesSelect);
    settingsContainer.appendChild(toggleButton);

    return settingsContainer;
  }

  _toggleLineNumbers = (thing) => {
    this.data.showlinenumbers = !this.data.showlinenumbers
    this.data.editorInstance.toggleLineNumbers()

    // console.log(this.data.editorInstance)
    // replace this with a native method for codeCup, if it gets implemented.
    // for now, we will completely destroy the codeCup instance, and rebuild it - lazy but effective


  }

  _updateLanguage = (lang) => {
    this.data.language = lang
    this._element.querySelector('.editorjs-codeCup_LangDisplay').innerHTML = this.data.language
    this.data.editorInstance.updateLanguage(this.data.language)
  }



  /**
   * Extract Tool's data from the view
   * @param {HTMLDivElement} toolsContent - EditorJsCodeCup tools rendered view
   * @returns {EditorJsCodeCupData} - saved data
   * @public
   */
  save(toolsContent) {
    let resp = {
      code : this.data.editorInstance.getCode(),
      language : this.data.language,
      showlinenumbers : this.data.showlinenumbers,
      showCopyButton : this.data.showCopyButton
    };

    return resp
  }

  /**
   * Returns true to notify the core that read-only mode is supported
   *
   * @return {boolean}
   */
  static get isReadOnlySupported() {
    return true;
  }


  /**
   * Icon and title for displaying at the Toolbox
   *
   * @return {{icon: string, title: string}}
   */
  static get toolbox() {
    return {
      icon: '<svg width="24" height="24" viewBox="-5 -6 24 24" xmlns="http://www.w3.org/2000/svg">\n' +
        '    <path style="stroke: none !important; fill: currentColor;" d="M3.177 6.852c.205.253.347.572.427.954.078.372.117.844.117 1.417 0 .418.01.725.03.92.02.18.057.314.107.396.046.075.093.117.14.134.075.027.218.056.42.083a.855.855 0 0 1 .56.297c.145.167.215.38.215.636 0 .612-.432.934-1.216.934-.457 0-.87-.087-1.233-.262a1.995 1.995 0 0 1-.853-.751 2.09 2.09 0 0 1-.305-1.097c-.014-.648-.029-1.168-.043-1.56-.013-.383-.034-.631-.06-.733-.064-.263-.158-.455-.276-.578a2.163 2.163 0 0 0-.505-.376c-.238-.134-.41-.256-.519-.371C.058 6.76 0 6.567 0 6.315c0-.37.166-.657.493-.846.329-.186.56-.342.693-.466a.942.942 0 0 0 .26-.447c.056-.2.088-.42.097-.658.01-.25.024-.85.043-1.802.015-.629.239-1.14.672-1.522C2.691.19 3.268 0 3.977 0c.783 0 1.216.317 1.216.921 0 .264-.069.48-.211.643a.858.858 0 0 1-.563.29c-.249.03-.417.076-.498.126-.062.04-.112.134-.139.291-.031.187-.052.562-.061 1.119a8.828 8.828 0 0 1-.112 1.378 2.24 2.24 0 0 1-.404.963c-.159.212-.373.406-.64.583.25.163.454.342.612.538zm7.34 0c.157-.196.362-.375.612-.538a2.544 2.544 0 0 1-.641-.583 2.24 2.24 0 0 1-.404-.963 8.828 8.828 0 0 1-.112-1.378c-.009-.557-.03-.932-.061-1.119-.027-.157-.077-.251-.14-.29-.08-.051-.248-.096-.496-.127a.858.858 0 0 1-.564-.29C8.57 1.401 8.5 1.185 8.5.921 8.5.317 8.933 0 9.716 0c.71 0 1.286.19 1.72.574.432.382.656.893.671 1.522.02.952.033 1.553.043 1.802.009.238.041.458.097.658a.942.942 0 0 0 .26.447c.133.124.364.28.693.466a.926.926 0 0 1 .493.846c0 .252-.058.446-.183.58-.109.115-.281.237-.52.371-.21.118-.377.244-.504.376-.118.123-.212.315-.277.578-.025.102-.045.35-.06.733-.013.392-.027.912-.042 1.56a2.09 2.09 0 0 1-.305 1.097c-.2.323-.486.574-.853.75a2.811 2.811 0 0 1-1.233.263c-.784 0-1.216-.322-1.216-.934 0-.256.07-.47.214-.636a.855.855 0 0 1 .562-.297c.201-.027.344-.056.418-.083.048-.017.096-.06.14-.134a.996.996 0 0 0 .107-.396c.02-.195.031-.502.031-.92 0-.573.039-1.045.117-1.417.08-.382.222-.701.427-.954z"></path>\n' +
        '</svg>\n',
      title: 'CodeCup'
    };
  }
}

export { EditorJsCodeCup as default }
