import { expect } from 'chai'

import {
  matchOutline,
  nestOutline,
} from '../../../../frontend/js/features/outline/outline-parser'

describe('OutlineParser', function () {
  describe('matchOutline', function () {
    it('matches all levels', function () {
      const content = `
      \\book{Book}
      \\part{Part}
      \\addpart{Part 2}
      \\chapter{Chapter}
      \\addchap{Chapter 2}
      \\section{Section 1}
      \\addsec{Section 1b}
      \\subsection{Subsection}
      \\subsubsection{Subsubsection}
      \\section{Section 2}
      \\subsubsection{Subsubsection without subsection}
      \\paragraph{a paragraph} Here is some text.
      \\subparagraph{a subparagraph} Here is some more text.
    `
      const outline = matchOutline(content)
      expect(outline).to.deep.equal([
        { line: 2, title: 'Book', level: 10 },
        { line: 3, title: 'Part', level: 20 },
        { line: 4, title: 'Part 2', level: 20 },
        { line: 5, title: 'Chapter', level: 30 },
        { line: 6, title: 'Chapter 2', level: 30 },
        { line: 7, title: 'Section 1', level: 40 },
        { line: 8, title: 'Section 1b', level: 40 },
        { line: 9, title: 'Subsection', level: 50 },
        { line: 10, title: 'Subsubsection', level: 60 },
        { line: 11, title: 'Section 2', level: 40 },
        { line: 12, title: 'Subsubsection without subsection', level: 60 },
        { line: 13, title: 'a paragraph', level: 70 },
        { line: 14, title: 'a subparagraph', level: 80 },
      ])
    })

    it('matches display titles', function () {
      const content = `
      \\section{\\label{foo} Label before}
      \\section{Label after \\label{foo}}
      \\section{Label \\label{foo} between}
      \\section{TT \\texttt{Bar}}
      \\section{plain title}
      `
      const outline = matchOutline(content)
      expect(outline).to.deep.equal([
        { line: 2, title: ' Label before', level: 40 },
        { line: 3, title: 'Label after ', level: 40 },
        { line: 4, title: 'Label  between', level: 40 },
        { line: 5, title: 'TT Bar', level: 40 },
        { line: 6, title: 'plain title', level: 40 },
      ])
    })

    it('removes spurious commands after title definition', function () {
      const content = `
      \\section{Plain title} more text \\href{link}{link}
      \\section{\\label{foo} Label before} more text \\href{link}{link}
      `
      const outline = matchOutline(content)
      expect(outline).to.deep.equal([
        { line: 2, title: 'Plain title', level: 40 },
        { line: 3, title: ' Label before', level: 40 },
      ])
    })

    it('matches empty sections', function () {
      const outline = matchOutline('\\section{}')
      expect(outline).to.deep.equal([{ line: 1, title: '', level: 40 }])
    })

    it('matches indented sections', function () {
      const outline = matchOutline('\t\\section{Indented}')
      expect(outline).to.deep.equal([{ line: 1, title: 'Indented', level: 40 }])
    })

    it('matches unnumbered sections', function () {
      const outline = matchOutline('\\section*{Unnumbered}')
      expect(outline).to.deep.equal([
        { line: 1, title: 'Unnumbered', level: 40 },
      ])
    })

    it('matches short titles', function () {
      const outline = matchOutline(
        '\\chapter[Short Title For TOC]{Very Long Title for Text}'
      )
      expect(outline).to.deep.equal([
        { line: 1, title: 'Short Title For TOC', level: 30 },
      ])
    })

    it('handles spacing', function () {
      const content = `
      \\section {Weird Spacing}
      \\section * {Weird Spacing Unnumbered}
      \\section [Weird Spacing for TOC] {Weird Spacing}
    `
      const outline = matchOutline(content)
      expect(outline).to.deep.equal([
        { line: 2, title: 'Weird Spacing', level: 40 },
        { line: 3, title: 'Weird Spacing Unnumbered', level: 40 },
        { line: 4, title: 'Weird Spacing for TOC', level: 40 },
      ])
    })

    it("doesn't match commented lines", function () {
      const content = `
      % \\section{I should not appear in the outline}
    `
      const outline = matchOutline(content)
      expect(outline).to.deep.equal([])
    })

    it("doesn't match inline sections", function () {
      const content = `
      I like to write \\section{inline} on one line.
    `
      const outline = matchOutline(content)
      expect(outline).to.deep.equal([])
    })
  })

  describe('nestOutline', function () {
    it('matches all levels', function () {
      const flatOutline = [
        { line: 10, title: 'Book', level: 10 },
        { line: 20, title: 'Part A', level: 20 },
        { line: 30, title: 'Section A 1', level: 40 },
        { line: 40, title: 'Subsection A 1 1', level: 50 },
        { line: 50, title: 'Subsection A 1 2', level: 50 },
        { line: 60, title: 'Section A 2', level: 40 },
        { line: 70, title: 'Section A 3', level: 40 },
        { line: 80, title: 'Subsection A 3 1', level: 50 },
        { line: 90, title: 'Chapter', level: 30 },
        { line: 100, title: 'Part B', level: 20 },
        { line: 110, title: 'Section 2', level: 40 },
        { line: 120, title: 'Subsubsection without subsection', level: 60 },
      ]
      const nestedOutline = nestOutline(flatOutline)
      expect(nestedOutline).to.deep.equal([
        {
          line: 10,
          title: 'Book',
          level: 10,
          children: [
            {
              line: 20,
              title: 'Part A',
              level: 20,
              children: [
                {
                  line: 30,
                  title: 'Section A 1',
                  level: 40,
                  children: [
                    { line: 40, title: 'Subsection A 1 1', level: 50 },
                    { line: 50, title: 'Subsection A 1 2', level: 50 },
                  ],
                },
                { line: 60, title: 'Section A 2', level: 40 },
                {
                  line: 70,
                  title: 'Section A 3',
                  level: 40,
                  children: [
                    { line: 80, title: 'Subsection A 3 1', level: 50 },
                  ],
                },
                { line: 90, title: 'Chapter', level: 30 },
              ],
            },
            {
              line: 100,
              title: 'Part B',
              level: 20,
              children: [
                {
                  line: 110,
                  title: 'Section 2',
                  level: 40,
                  children: [
                    {
                      line: 120,
                      title: 'Subsubsection without subsection',
                      level: 60,
                    },
                  ],
                },
              ],
            },
          ],
        },
      ])
    })
  })
})
