const assert = require('assert')
const { join, resolve } = require('path')

const PageUtil = require('../src/page')

const { testProjectPath } = require('../../../test/support/paths')
const pagesPath = resolve(testProjectPath, 'uiengine', 'pages')

describe('PageUtil', () => {
  describe('#pageIdToPath', () => {
    it('should return empty path for index page', () => {
      assert.strictEqual(PageUtil.pageIdToPath('index'), '')
    })

    it('should return path for page', () => {
      assert.strictEqual(PageUtil.pageIdToPath('patterns/atoms/buttons'), 'patterns/atoms/buttons')
    })
  })

  describe('#pageIdToTitle', () => {
    it('should return titleized name', () => {
      assert.strictEqual(PageUtil.pageIdToTitle('index'), 'Home')
      assert.strictEqual(PageUtil.pageIdToTitle('patterns/atoms'), 'Atoms')
      assert.strictEqual(PageUtil.pageIdToTitle('pattern-library'), 'Pattern Library')
    })
  })

  describe('#pageIdToFilePath', () => {
    it('should return page file path for index page', () => {
      assert.strictEqual(
        PageUtil.pageIdToFilePath(pagesPath, 'index'),
        join(pagesPath, 'page.config.js')
      )
    })

    it('should return page file path for page', () => {
      assert.strictEqual(
        PageUtil.pageIdToFilePath(pagesPath, 'patterns/atoms/buttons'),
        join(pagesPath, 'patterns', 'atoms', 'buttons', 'page.config.js')
      )
    })
  })

  describe('#pageFilePathToId', () => {
    it('should return page id for index file path', () => {
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, join(pagesPath, 'page.config.js')), 'index')
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, join(pagesPath, 'README.md')), 'index')
    })

    it('should return page id for page file path', () => {
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, join(pagesPath, 'patterns', 'atoms', 'copytext', 'page.config.js')), 'patterns/atoms/copytext')
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, join(pagesPath, 'patterns', 'atoms', 'copytext', 'README.md')), 'patterns/atoms/copytext')
    })

    it('should return page id for file path', () => {
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, join(pagesPath, 'testcases', 'index.txt')), 'testcases')
    })

    it('should return page id for nested file path', () => {
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, join(pagesPath, 'static', 'additional.pdf')), 'index')
    })

    it('should return page id for nested file path without direct parent', () => {
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, join(pagesPath, 'static', 'test', 'nested', 'additional.pdf')), 'index')
    })

    it('should return null for invalid file path', () => {
      const filePath = resolve(testProjectPath, 'src', 'components', 'component.config.js')
      assert.strictEqual(PageUtil.pageFilePathToId(pagesPath, filePath), null)
    })
  })

  describe('#parentIdForPageId', () => {
    it('should return null for index page id', () => {
      const pageIds = ['index']
      assert.strictEqual(PageUtil.parentIdForPageId(pageIds, 'index'), null)
    })

    it('should return parent page id for page id', () => {
      const pageIds = ['index', 'patterns', 'patterns/atoms', 'patterns/atoms/buttons']
      assert.strictEqual(PageUtil.parentIdForPageId(pageIds, 'patterns/atoms/buttons'), 'patterns/atoms')
    })

    it('should return next parent page id for page id with no intermediate parent', () => {
      const pageIds = ['index', 'patterns/atoms/buttons']
      assert.strictEqual(PageUtil.parentIdForPageId(pageIds, 'patterns/atoms/buttons'), 'index')
    })
  })

  describe('#pageIdForComponentId', () => {
    it('should convert the component id into a page id based on the parent page id for index page', () => {
      const pageId = PageUtil.pageIdForComponentId('index', 'button')
      assert.strictEqual(pageId, 'button')
    })

    it('should convert the component id into a page id based on the parent page id for child page', () => {
      const pageId = PageUtil.pageIdForComponentId('patterns/atoms', 'button')
      assert.strictEqual(pageId, 'patterns/atoms/button')
    })
  })

  describe('#pagePathForComponentId', () => {
    it('should convert the component id into a page path based on the parent page path for index page', () => {
      const pagePath = PageUtil.pagePathForComponentId('', 'button')
      assert.strictEqual(pagePath, 'button')
    })

    it('should convert the component id into a page path based on the parent page path for child page', () => {
      const pagePath = PageUtil.pagePathForComponentId('patterns/atoms', 'button')
      assert.strictEqual(pagePath, 'patterns/atoms/button')
    })
  })

  describe('#convertUserProvidedChildrenList', () => {
    it('should convert the children list provided by the user to childIds for index page', () => {
      const availableChildIds = ['docs', 'patterns']
      const attrs = { children: availableChildIds.reverse() }
      const { childIds } = PageUtil.convertUserProvidedChildrenList('index', availableChildIds, attrs)
      assert.strictEqual(childIds[0], 'patterns')
      assert.strictEqual(childIds[1], 'docs')
    })

    it('should convert a prefixed children list provided by the user to childIds for child page', () => {
      const availableChildIds = ['patterns/atoms', 'patterns/molecules']
      const attrs = { children: availableChildIds }
      const { childIds } = PageUtil.convertUserProvidedChildrenList('patterns', availableChildIds, attrs)
      assert.strictEqual(childIds[0], 'patterns/atoms')
      assert.strictEqual(childIds[1], 'patterns/molecules')
    })

    it('should convert a non-prefixed children list provided by the user to childIds for child page', () => {
      const availableChildIds = ['patterns/atoms', 'patterns/molecules']
      const children = ['atoms', 'molecules']
      const attrs = { children }
      const { childIds } = PageUtil.convertUserProvidedChildrenList('patterns', availableChildIds, attrs)
      assert.strictEqual(childIds[0], 'patterns/atoms')
      assert.strictEqual(childIds[1], 'patterns/molecules')
    })

    it('should return the attributes as they are if the children list is not provided by the user', () => {
      const availableChildIds = ['docs', 'patterns']
      const attrs = { title: 'No children' }
      const converted = PageUtil.convertUserProvidedChildrenList('index', availableChildIds, attrs)
      assert.strictEqual(attrs, converted)
    })

    it('should throw an error if a child does not exist', () => {
      const availableChildIds = ['atoms']
      const attrs = { children: ['atoms', 'doesnotexist'] }

      assert.throws(() => PageUtil.convertUserProvidedChildrenList('patterns', availableChildIds, attrs))
    })
  })

  describe('#convertUserProvidedComponentsList', () => {
    it('should convert the components list provided by the user to componentIds for index page', () => {
      const attrs = { components: ['link', 'button'] }
      const { componentIds } = PageUtil.convertUserProvidedComponentsList('index', attrs)
      assert.strictEqual(componentIds[0], 'link')
      assert.strictEqual(componentIds[1], 'button')
    })

    it('should convert the components list provided by the user to componentIds for child page', () => {
      const attrs = { components: ['link', 'button'] }
      const { componentIds } = PageUtil.convertUserProvidedComponentsList('patterns/atoms', attrs)
      assert.strictEqual(componentIds[0], 'link')
      assert.strictEqual(componentIds[1], 'button')
    })

    it('should return the attributes as they are if the components list is not provided by the user', () => {
      const attrs = { title: 'No components' }
      const converted = PageUtil.convertUserProvidedComponentsList('index', attrs)
      assert.strictEqual(attrs, converted)
    })
  })

  describe('#isDocumentationPage', () => {
    it('should only return true if page type is "documentation"', () => {
      assert(PageUtil.isDocumentationPage('documentation'))
      assert(!PageUtil.isDocumentationPage('template'))
      assert(!PageUtil.isDocumentationPage('tokens'))
    })
  })

  describe('#isTokensPage', () => {
    it('should only return true if page type is "tokens"', () => {
      assert(PageUtil.isTokensPage('tokens'))
      assert(!PageUtil.isTokensPage('template'))
      assert(!PageUtil.isTokensPage('documentation'))
    })
  })

  describe('#determineType', () => {
    it('should return "template" if page attributes has template', () => {
      assert.strictEqual('template', PageUtil.determineType({ template: 'custom.pug' }))
    })

    it('should return "template" if page attributes has fragment', () => {
      assert.strictEqual('template', PageUtil.determineType({ fragment: 'fragment.pug' }))
    })

    it('should return "tokens" if page attributes has tokens', () => {
      assert.strictEqual('tokens', PageUtil.determineType({ tokens: {} }))
    })

    it('should return "documentation" if page attributes has neither template nor tokens', () => {
      assert.strictEqual('documentation', PageUtil.determineType({}))
    })
  })
})
