text: /* eslint-disable @typescript-eslint/no-use-before-define */
  import { Component, domHelpers, DefaultDOMElement } from 'substance';
  import { ValueComponent, renderModel, createValueModel } from '../../kit';
  
  // TODO: this needs to be redesigned
  // TODO: we should follow the same approach as in Metadata, i.e. having a model which is a list of sections
  export default class ManuscriptTOC extends Component {
    render($$) {
      const el = $$('div').addClass('sc-toc');
      const manuscriptModel = this.props.model;
  
      const tocEntries = $$('div')
        .addClass('se-toc-entries')
        .ref('tocEntries')
        .on('click', domHelpers.stop);
  
      tocEntries.append(
        $$(SectionTOCEntry, {
          label: this.getLabel('title'),
          section: 'title',
        }),
      );
  
      tocEntries.append(
        $$(SectionTOCEntry, {
          label: this.getLabel('abstract'),
          section: 'abstract',
        }),
      );
  
      tocEntries.append(
        $$(BodyTOCEntry, {
          label: this.getLabel('body'),
          model: manuscriptModel.getBody(),
        }),
      );
  
      tocEntries.append(
        $$(DynamicTOCEntry, {
          label: this.getLabel('footnotes-label'),
          model: manuscriptModel.getFootnotes(),
          section: 'footnotes',
        }),
      );
  
      tocEntries.append(
        $$(DynamicTOCEntry, {
          label: this.getLabel('references-label'),
          model: manuscriptModel.getReferences(),
          section: 'references',
        }),
      );
  
      tocEntries.append(
        $$(SectionTOCEntry, {
          label: this.getLabel('acknowledgement'),
          section: 'acknowledgements',
        }),
      );
  
      tocEntries.append(
        $$(SectionTOCEntry, {
          label: this.getLabel('author-details-label'),
          section: 'author-details',
        }),
      );
  
      tocEntries.append(
        $$(SectionTOCEntry, {
          label: this.getLabel('article-information-label'),
          section: 'article-information',
        }),
      );
  
      el.append(tocEntries);
  
      return el;
    }
  
    onTOCUpdated() {
      this.rerender();
    }
  }
  
  class SectionTOCEntry extends Component {
    render($$) {
      const { label, section } = this.props;
      const el = $$('a')
        .addClass('sc-toc-entry sm-level-1')
        .attr({ 'data-section': section })
        .on('click', this._onClick)
        .append(label);
      return el;
    }
  
    _onClick(event) {
      event.preventDefault();
      event.stopPropagation();
      this.send('scrollTo', { section: this.props.section });
    }
  }
  
  class BodyTOCEntry extends ValueComponent {
    render($$) {
      const items = this.props.model.getItems();
      const headings = items.filter(node => node.type === 'heading');
      return $$('div')
        .addClass('sc-toc-entry')
        .append(
          headings.map(heading => {
            const el = $$(TOCHeadingEntry, { node: heading })
              .ref(heading.id)
              .addClass(`sc-toc-entry sm-level-${heading.level}`)
              .attr({ 'data-id': heading.id })
              .on('click', this._onClick);
            return el;
          }),
        );
    }
  
    _onClick(event) {
      const target = DefaultDOMElement.wrap(event.currentTarget);
      const nodeId = target.attr('data-id');
      event.preventDefault();
      event.stopPropagation();
      this.send('scrollTo', { nodeId });
    }
  }
  
  class TOCHeadingEntry extends Component {
    didMount() {
      this.context.editorState.addObserver(['document'], this.rerender, this, {
        stage: 'render',
        document: { path: [this.props.node.id] },
      });
    }
    dispose() {
      this.context.editorState.removeObserver(this);
    }
    render($$) {
      const api = this.context.api;
      const heading = this.props.node;
      return $$('div').append(renderModel($$, this, createValueModel(api, heading.getPath()), { readOnly: true }));
    }
  }
  
  // only visible when collection not empty
  class DynamicTOCEntry extends ValueComponent {
    render($$) {
      const { label, model, section } = this.props;
      const el = $$('div')
        .addClass('sc-toc-entry sm-level-1')
        .attr({ 'data-section': section })
        .on('click', this._onClick)
        .append(label);
      if (model.length === 0) {
        el.addClass('sm-hidden');
      }
      return el;
    }
  
    _onClick(event) {
      event.preventDefault();
      event.stopPropagation();
      this.send('scrollTo', { section: this.props.section });
    }
  }
  