/* eslint-env jest */
import { getSortedRoutes } from 'next/dist/shared/lib/router/utils/sorted-routes'

describe('getSortedRoutes', () => {
  it('does not add extra routes', () => {
    expect(getSortedRoutes(['/posts'])).toEqual(['/posts'])

    expect(getSortedRoutes(['/posts/[id]'])).toEqual(['/posts/[id]'])
    expect(getSortedRoutes(['/posts/[id]/foo'])).toEqual(['/posts/[id]/foo'])

    expect(getSortedRoutes(['/posts/[id]/[foo]/bar'])).toEqual([
      '/posts/[id]/[foo]/bar',
    ])
    expect(getSortedRoutes(['/posts/[id]/baz/[foo]/bar'])).toEqual([
      '/posts/[id]/baz/[foo]/bar',
    ])
  })

  it('correctly sorts required slugs', () => {
    expect(
      getSortedRoutes([
        '/posts',
        '/[root-slug]',
        '/',
        '/posts/[id]',
        '/blog/[id]/comments/[cid]',
        '/blog/abc/[id]',
        '/[...rest]',
        '/blog/abc/post',
        '/blog/abc',
        '/p1/[[...incl]]',
        '/p/[...rest]',
        '/p2/[...rest]',
        '/p2/[id]',
        '/p2/[id]/abc',
        '/p3/[[...rest]]',
        '/p3/[id]',
        '/p3/[id]/abc',
        '/blog/[id]',
        '/foo/[d]/bar/baz/[f]',
        '/apples/[ab]/[cd]/ef',
      ])
    ).toMatchInlineSnapshot(`
      Array [
        "/",
        "/apples/[ab]/[cd]/ef",
        "/blog/abc",
        "/blog/abc/post",
        "/blog/abc/[id]",
        "/blog/[id]",
        "/blog/[id]/comments/[cid]",
        "/foo/[d]/bar/baz/[f]",
        "/p/[...rest]",
        "/p1/[[...incl]]",
        "/p2/[id]",
        "/p2/[id]/abc",
        "/p2/[...rest]",
        "/p3/[id]",
        "/p3/[id]/abc",
        "/p3/[[...rest]]",
        "/posts",
        "/posts/[id]",
        "/[root-slug]",
        "/[...rest]",
      ]
    `)
  })

  it('catches mismatched param names', () => {
    expect(() =>
      getSortedRoutes([
        '/',
        '/blog',
        '/blog/[id]',
        '/blog/[id]/comments/[cid]',
        '/blog/[cid]',
      ])
    ).toThrowError(/different slug names/)
  })

  it('catches reused param names', () => {
    expect(() =>
      getSortedRoutes(['/', '/blog', '/blog/[id]/comments/[id]', '/blog/[id]'])
    ).toThrowError(/the same slug name/)
  })

  it('catches reused param names with catch-all', () => {
    expect(() =>
      getSortedRoutes(['/blog/[id]', '/blog/[id]/[...id]'])
    ).toThrowError(/the same slug name/)
  })

  it('catches middle catch-all with another catch-all', () => {
    expect(() =>
      getSortedRoutes(['/blog/[...id]/[...id2]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Catch-all must be the last part of the URL."`
    )
  })

  it('catches middle catch-all with fixed route', () => {
    expect(() =>
      getSortedRoutes(['/blog/[...id]/abc'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Catch-all must be the last part of the URL."`
    )
  })

  it('catches extra dots in catch-all', () => {
    expect(() =>
      getSortedRoutes(['/blog/[....id]/abc'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Segment names may not start with erroneous periods ('.id')."`
    )
  })

  it('catches missing dots in catch-all', () => {
    expect(() =>
      getSortedRoutes(['/blog/[..id]/abc'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Segment names may not start with erroneous periods ('..id')."`
    )
  })

  it('catches extra brackets for optional', () => {
    expect(() =>
      getSortedRoutes(['/blog/[[...id]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Segment names may not start or end with extra brackets ('[...id')."`
    )
    expect(() =>
      getSortedRoutes(['/blog/[[[...id]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Segment names may not start or end with extra brackets ('[...id')."`
    )
    expect(() =>
      getSortedRoutes(['/blog/[...id]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Segment names may not start or end with extra brackets ('id]')."`
    )
    expect(() =>
      getSortedRoutes(['/blog/[[...id]]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Segment names may not start or end with extra brackets ('id]')."`
    )
    expect(() =>
      getSortedRoutes(['/blog/[[[...id]]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Segment names may not start or end with extra brackets ('[...id]')."`
    )
  })

  it('disallows optional params', () => {
    expect(() =>
      getSortedRoutes(['/[[blog]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Optional route parameters are not yet supported (\\"[[blog]]\\")."`
    )
    expect(() =>
      getSortedRoutes(['/abc/[[blog]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Optional route parameters are not yet supported (\\"[[blog]]\\")."`
    )
    expect(() =>
      getSortedRoutes(['/abc/[[blog]]/def'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"Optional route parameters are not yet supported (\\"[[blog]]\\")."`
    )
  })

  it('disallows mixing required catch all and optional catch all', () => {
    expect(() =>
      getSortedRoutes(['/[...one]', '/[[...one]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"You cannot use both an required and optional catch-all route at the same level (\\"[...one]\\" and \\"[[...one]]\\" )."`
    )
    expect(() =>
      getSortedRoutes(['/[[...one]]', '/[...one]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"You cannot use both an optional and required catch-all route at the same level (\\"[[...one]]\\" and \\"[...one]\\")."`
    )
  })

  it('disallows apex and optional catch all', () => {
    expect(() =>
      getSortedRoutes(['/', '/[[...all]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"You cannot define a route with the same specificity as a optional catch-all route (\\"/\\" and \\"/[[...all]]\\")."`
    )
    expect(() =>
      getSortedRoutes(['/[[...all]]', '/'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"You cannot define a route with the same specificity as a optional catch-all route (\\"/\\" and \\"/[[...all]]\\")."`
    )

    expect(() =>
      getSortedRoutes(['/sub', '/sub/[[...all]]'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"You cannot define a route with the same specificity as a optional catch-all route (\\"/sub\\" and \\"/sub[[...all]]\\")."`
    )
    expect(() =>
      getSortedRoutes(['/sub/[[...all]]', '/sub'])
    ).toThrowErrorMatchingInlineSnapshot(
      `"You cannot define a route with the same specificity as a optional catch-all route (\\"/sub\\" and \\"/sub[[...all]]\\")."`
    )
  })

  it('catches param names differing only by non-word characters', () => {
    expect(() =>
      getSortedRoutes([
        '/blog/[helloworld]',
        '/blog/[helloworld]/[hello-world]',
      ])
    ).toThrowError(/differ only by non-word/)
  })
})
