import './bpmn.scss';
import cloneDeep from 'lodash/cloneDeep';
import 'bpmn-js/dist/assets/bpmn-js.css';
import 'bpmn-js/dist/assets/diagram-js.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';

const icon = '<svg height="24" width="24" viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg"><path d="m96-593.63783v1280h1856v-1280zm1756 97.69925v1091.54297h-1372v-1091.54103l1372-.002zm-1660 .002 192-.00021v1091.54108l-192 .00021z" transform="translate(0 995.63783)"/></svg>';
const xml = '<?xml version="1.0" encoding="UTF-8"?>\n' +
  '<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="sample-diagram" targetNamespace="http://bpmn.io/schema/bpmn">\n' +
  '  <bpmn2:process id="Process_1" isExecutable="false">\n' +
  '    <bpmn2:startEvent id="StartEvent_1"/>\n' +
  '  </bpmn2:process>\n' +
  '  <bpmndi:BPMNDiagram id="BPMNDiagram_1">\n' +
  '    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">\n' +
  '      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">\n' +
  '        <dc:Bounds height="36.0" width="36.0" x="412.0" y="240.0"/>\n' +
  '      </bpmndi:BPMNShape>\n' +
  '    </bpmndi:BPMNPlane>\n' +
  '  </bpmndi:BPMNDiagram>\n' +
  '</bpmn2:definitions>';

export default class Bpmn {
  data = null;
  readOnly = false;

  static get sanitize(){
    return {
      svg: true,
      xml: true,
      caption: {} // only tags from Inline Toolbar
    }
  }

  /**
   * Allow to use this tool in read only mode
   */
  static get isReadOnlySupported() {
    return true;
  }

  constructor({ data, readOnly }){
    this.data = data;
    this.readOnly = readOnly;
  }

  static get toolbox() {
    return {
      title: 'BPMN',
      icon
    };
  }

  render(){
    const wrapper = createWrapper(this.data, this.readOnly);
    if (!this.readOnly) {
      wrapper.classList.remove('readonly');
      wrapper.addEventListener('dblclick', async () => {
        const modal = document.createElement('div');
        modal.classList.add('itf-modal');
        modal.classList.add('modal');
        modal.classList.add('fade');
        modal.classList.add('editorjs-bpmn-modal');
        const modalDialog = document.createElement('div');
        modalDialog.classList.add('modal-dialog');
        modalDialog.classList.add('modal-fullscreen');
        const modalContent = document.createElement('div');
        modalContent.classList.add('modal-content');
        const modalHeader = document.createElement('div');
        modalHeader.classList.add('modal-header');
        const modalTitle = document.createElement('h5');
        modalTitle.classList.add('modal-title');
        modalTitle.textContent = 'BPMN Editor';
        modalHeader.appendChild(modalTitle);
        const btnHolder = document.createElement('div');
        btnHolder.classList.add('d-flex');
        const modalSaveBtn = document.createElement('button');
        modalSaveBtn.classList.add('btn');
        modalSaveBtn.classList.add('btn-primary');
        modalSaveBtn.classList.add('itf-button');
        modalSaveBtn.textContent = 'Save & Close';
        const modalCancelBtn = document.createElement('button');
        modalCancelBtn.classList.add('btn');
        modalCancelBtn.classList.add('btn-secondary');
        modalCancelBtn.classList.add('itf-button');
        modalCancelBtn.classList.add('me-2');
        modalCancelBtn.textContent = 'Cancel';
        btnHolder.appendChild(modalCancelBtn);
        btnHolder.appendChild(modalSaveBtn);
        modalHeader.appendChild(modalTitle);
        modalHeader.appendChild(btnHolder);
        modalContent.appendChild(modalHeader);
        const modalBody = document.createElement('div');
        modalBody.classList.add('modal-body');
        const frame = document.createElement('div');
        modalBody.appendChild(frame);
        modalContent.appendChild(modalBody);
        modalDialog.appendChild(modalContent);
        modal.appendChild(modalDialog);
        document.body.appendChild(modal);
        const {default: Modal} = await import('../../../modal/modalSrc');
        const modalEl = new Modal(modal, {context: document.body, backdrop: 'static'});
        modalEl.show();
        modal.addEventListener('hidden.bs.modal', () => {
          document.body.removeChild(modal);
        });

        frame.classList.add('modal-body-content');

        let modeler;
        setTimeout(async () => {
          const { default: BpmnModeler } = await import('bpmn-js/dist/bpmn-modeler.production.min');
          modeler = new BpmnModeler({
            container: frame,
            keyboard: {
              bindTo: window
            }
          });

          try {
            await modeler.importXML(this.data?.xml || xml);
          } catch (err) {
            console.error('error loading BPMN 2.0 XML', err);
          }
        }, 500)

        modalSaveBtn.addEventListener('click', async () => {
          this.data = {
            svg: (await modeler.saveSVG())?.svg,
            xml: (await modeler.saveXML({ format: true }))?.xml
          };
          if (this.data.svg) {
            createSvg(wrapper, this.data, this.readOnly);
          }
          modalEl.hide();
        });
        modalCancelBtn.addEventListener('click', () => {
          modalEl.hide();
        });
      });
    } else {
      wrapper.classList.add('readonly');
    }
    return wrapper;

    function createWrapper(data, readOnly) {
      const wrapper = document.createElement('div');
      wrapper.classList.add('editorjs-bpmn');
      if (data.svg) {
        wrapper.classList.remove('empty');
        createSvg(wrapper, data, readOnly);
      } else if (!readOnly) {
        wrapper.classList.add('empty');
        wrapper.innerHTML = `<div class="text-muted icon me-2">${icon}</div><div class="text-muted text">Double click to start diagramming your business processes.</div>`;
      }
      return wrapper;
    }

    function createSvg(wrapper, { svg, caption }, readOnly) {
      const svgContainer = document.createElement('div');
      svgContainer.innerHTML = svg;

      const divSvg = document.createElement('div');
      wrapper.innerHTML = '';
      wrapper.classList.remove('empty');
      wrapper.appendChild(divSvg);
      divSvg.appendChild(svgContainer);

      const captionEl = document.createElement('div');
      captionEl.contentEditable = !readOnly;
      captionEl.classList.add('editorjs-bpmn-caption');
      captionEl.textContent = caption;
      if (!readOnly) {
        captionEl.setAttribute('data-text', 'Caption');
        captionEl.addEventListener('dblclick', (e) => {
          e.stopPropagation();
        });
      }
      wrapper.appendChild(captionEl);
    }
  }
  save(blockContent){
    const caption = blockContent.querySelector('[contenteditable]');
    const data = cloneDeep(this.data);
    data.caption = caption ? caption.innerHTML : '';
    return data;
  }
}
