// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package page_test

import (
	"strings"
	"testing"

	"github.com/bep/logg"
	qt "github.com/frankban/quicktest"
	"github.com/gohugoio/hugo/htesting"
	"github.com/gohugoio/hugo/hugolib"
)

func TestPermalinks(t *testing.T) {
	t.Parallel()

	files := `
-- layouts/list.html --
List|{{ .Kind }}|{{ .RelPermalink }}|
-- layouts/single.html --
Single|{{ .Kind }}|{{ .RelPermalink }}|
-- hugo.toml --
[taxonomies]
tag = "tags"
[permalinks.page]
withpageslug = '/pageslug/:slug/'
withallbutlastsection = '/:sections[:last]/:slug/'
withallbutlastsectionslug = '/:sectionslugs[:last]/:slug/'
withsectionslug = '/sectionslug/:sectionslug/:slug/'
withsectionslugs = '/sectionslugs/:sectionslugs/:slug/'
[permalinks.section]
withfilefilename = '/sectionwithfilefilename/:contentbasename/'
withfilefiletitle = '/sectionwithfilefiletitle/:title/'
withfileslug = '/sectionwithfileslug/:slug/'
nofileslug = '/sectionnofileslug/:slug/'
nofilefilename = '/sectionnofilefilename/:contentbasename/'
nofiletitle1 = '/sectionnofiletitle1/:title/'
nofiletitle2 = '/sectionnofiletitle2/:sections[:last]/'
[permalinks.term]
tags = '/tagsslug/tag/:slug/'
[permalinks.taxonomy]
tags = '/tagsslug/:slug/'
-- content/withpageslug/p1.md --
---
slug: "p1slugvalue"
tags: ["mytag"]
---
-- content/withfilefilename/_index.md --
-- content/withfileslug/_index.md --
---
slug: "withfileslugvalue"
---
-- content/nofileslug/p1.md --
-- content/nofilefilename/p1.md --
-- content/nofiletitle1/p1.md --
-- content/nofiletitle2/asdf/p1.md --
-- content/withallbutlastsection/subsection/p1.md --
-- content/withallbutlastsectionslug/_index.md --
---
slug: "root-section-slug"
---
-- content/withallbutlastsectionslug/subsection/_index.md --
---
slug: "sub-section-slug"
---
-- content/withallbutlastsectionslug/subsection/p1.md --
---
slug: "page-slug"
---
-- content/withsectionslug/_index.md --
---
slug: "section-root-slug"
---
-- content/withsectionslug/subsection/_index.md --
-- content/withsectionslug/subsection/p1.md --
---
slug: "page1-slug"
---
-- content/withsectionslugs/_index.md --
---
slug: "sections-root-slug"
---
-- content/withsectionslugs/level1/_index.md --
---
slug: "level1-slug"
---
-- content/withsectionslugs/level1/p1.md --
---
slug: "page1-slug"
---
-- content/tags/_index.md --
---
slug: "tagsslug"
---
-- content/tags/mytag/_index.md --
---
slug: "mytagslug"
---


`

	b := hugolib.NewIntegrationTestBuilder(
		hugolib.IntegrationTestConfig{
			T:           t,
			TxtarString: files,
			LogLevel:    logg.LevelWarn,
		}).Build()

	t.Log(b.LogString())
	// No .File.TranslationBaseName on zero object etc. warnings.
	b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 0)
	b.AssertFileContent("public/pageslug/p1slugvalue/index.html", "Single|page|/pageslug/p1slugvalue/|")
	b.AssertFileContent("public/sectionslug/section-root-slug/page1-slug/index.html", "Single|page|/sectionslug/section-root-slug/page1-slug/|")
	b.AssertFileContent("public/sectionslugs/sections-root-slug/level1-slug/page1-slug/index.html", "Single|page|/sectionslugs/sections-root-slug/level1-slug/page1-slug/|")

	b.AssertFileContent("public/sectionwithfilefilename/withfilefilename/index.html", "List|section|/sectionwithfilefilename/withfilefilename/|")

	b.AssertFileContent("public/sectionwithfileslug/withfileslugvalue/index.html", "List|section|/sectionwithfileslug/withfileslugvalue/|")

	b.AssertFileContent("public/sectionnofilefilename/nofilefilename/index.html", "List|section|/sectionnofilefilename/nofilefilename/|")
	b.AssertFileContent("public/sectionnofileslug/nofileslugs/index.html", "List|section|/sectionnofileslug/nofileslugs/|")
	b.AssertFileContent("public/sectionnofiletitle1/nofiletitle1s/index.html", "List|section|/sectionnofiletitle1/nofiletitle1s/|")
	b.AssertFileContent("public/sectionnofiletitle2/index.html", "List|section|/sectionnofiletitle2/|")

	b.AssertFileContent("public/tagsslug/tag/mytagslug/index.html", "List|term|/tagsslug/tag/mytagslug/|")
	b.AssertFileContent("public/tagsslug/tagsslug/index.html", "List|taxonomy|/tagsslug/tagsslug/|")

	permalinksConf := b.H.Configs.Base.Permalinks
	b.Assert(permalinksConf, qt.DeepEquals, map[string]map[string]string{
		"page":     {"withallbutlastsection": "/:sections[:last]/:slug/", "withallbutlastsectionslug": "/:sectionslugs[:last]/:slug/", "withpageslug": "/pageslug/:slug/", "withsectionslug": "/sectionslug/:sectionslug/:slug/", "withsectionslugs": "/sectionslugs/:sectionslugs/:slug/"},
		"section":  {"nofilefilename": "/sectionnofilefilename/:contentbasename/", "nofileslug": "/sectionnofileslug/:slug/", "nofiletitle1": "/sectionnofiletitle1/:title/", "nofiletitle2": "/sectionnofiletitle2/:sections[:last]/", "withfilefilename": "/sectionwithfilefilename/:contentbasename/", "withfilefiletitle": "/sectionwithfilefiletitle/:title/", "withfileslug": "/sectionwithfileslug/:slug/"},
		"taxonomy": {"tags": "/tagsslug/:slug/"},
		"term":     {"tags": "/tagsslug/tag/:slug/"},
	})
}

func TestPermalinksOldSetup(t *testing.T) {
	t.Parallel()

	files := `
-- layouts/list.html --
List|{{ .Kind }}|{{ .RelPermalink }}|
-- layouts/single.html --
Single|{{ .Kind }}|{{ .RelPermalink }}|
-- hugo.toml --
[permalinks]
withpageslug = '/pageslug/:slug/'
-- content/withpageslug/p1.md --
---
slug: "p1slugvalue"
---




`

	b := hugolib.NewIntegrationTestBuilder(
		hugolib.IntegrationTestConfig{
			T:           t,
			TxtarString: files,
			LogLevel:    logg.LevelWarn,
		}).Build()

	t.Log(b.LogString())
	// No .File.TranslationBaseName on zero object etc. warnings.
	b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 0)
	b.AssertFileContent("public/pageslug/p1slugvalue/index.html", "Single|page|/pageslug/p1slugvalue/|")

	permalinksConf := b.H.Configs.Base.Permalinks
	b.Assert(permalinksConf, qt.DeepEquals, map[string]map[string]string{
		"page":     {"withpageslug": "/pageslug/:slug/"},
		"section":  {},
		"taxonomy": {},
		"term":     {"withpageslug": "/pageslug/:slug/"},
	})
}

func TestPermalinksNestedSections(t *testing.T) {
	t.Parallel()

	files := `
-- hugo.toml --
[permalinks.page]
books = '/libros/:sections[1:]/:contentbasename'

[permalinks.section]
books = '/libros/:sections[1:]'
-- content/books/_index.md --
---
title: Books
---
-- content/books/fiction/_index.md --
---
title: Fiction
---
-- content/books/fiction/2023/_index.md --
---
title: 2023
---
-- content/books/fiction/2023/book1/index.md --
---
title: Book 1
---
-- layouts/single.html --
Single.
-- layouts/list.html --
List.
`

	b := hugolib.NewIntegrationTestBuilder(
		hugolib.IntegrationTestConfig{
			T:           t,
			TxtarString: files,
			LogLevel:    logg.LevelWarn,
		}).Build()

	t.Log(b.LogString())
	// No .File.TranslationBaseName on zero object etc. warnings.
	b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 0)

	b.AssertFileContent("public/libros/index.html", "List.")
	b.AssertFileContent("public/libros/fiction/index.html", "List.")
	b.AssertFileContent("public/libros/fiction/2023/book1/index.html", "Single.")
}

func TestPermalinksNestedSectionsWithSlugs(t *testing.T) {
	t.Parallel()

	files := `
-- hugo.toml --
[permalinks.page]
books = '/libros/:sectionslugs[1:]/:slug'

[permalinks.section]
books = '/libros/:sectionslugs[1:]'
-- content/books/_index.md --
---
title: Books
---
-- content/books/fiction/_index.md --
---
title: Fiction
slug: fictionslug
---
-- content/books/fiction/2023/_index.md --
---
title: 2023
---
-- content/books/fiction/2023/book1/index.md --
---
title: Book One
---
-- layouts/single.html --
Single.
-- layouts/list.html --
List.
`

	b := hugolib.NewIntegrationTestBuilder(
		hugolib.IntegrationTestConfig{
			T:           t,
			TxtarString: files,
			LogLevel:    logg.LevelWarn,
		}).Build()

	t.Log(b.LogString())
	// No .File.TranslationBaseName on zero object etc. warnings.
	b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 0)

	b.AssertFileContent("public/libros/index.html", "List.")
	b.AssertFileContent("public/libros/fictionslug/index.html", "List.")
	b.AssertFileContent("public/libros/fictionslug/2023/book-one/index.html", "Single.")
}

func TestPermalinksUrlCascade(t *testing.T) {
	t.Parallel()

	files := `
-- layouts/list.html --
List|{{ .Kind }}|{{ .RelPermalink }}|
-- layouts/single.html --
Single|{{ .Kind }}|{{ .RelPermalink }}|
-- hugo.toml --
-- content/cooking/delicious-recipes/_index.md --
---
url: /delicious-recipe/
cascade:
  url: /delicious-recipe/:slug/
---
-- content/cooking/delicious-recipes/example1.md --
---
title: Recipe 1
---
-- content/cooking/delicious-recipes/example2.md --
---
title: Recipe 2
slug: custom-recipe-2
---
`
	b := hugolib.NewIntegrationTestBuilder(
		hugolib.IntegrationTestConfig{
			T:           t,
			TxtarString: files,
			LogLevel:    logg.LevelWarn,
		}).Build()

	t.Log(b.LogString())
	b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 0)
	b.AssertFileContent("public/delicious-recipe/index.html", "List|section|/delicious-recipe/")
	b.AssertFileContent("public/delicious-recipe/recipe-1/index.html", "Single|page|/delicious-recipe/recipe-1/")
	b.AssertFileContent("public/delicious-recipe/custom-recipe-2/index.html", "Single|page|/delicious-recipe/custom-recipe-2/")
}

// Issue 12948.
// Issue 12954.
func TestPermalinksWithEscapedColons(t *testing.T) {
	t.Parallel()

	if htesting.IsWindows() {
		t.Skip("Windows does not support colons in paths")
	}

	files := `
-- hugo.toml --
disableKinds = ['home','rss','sitemap','taxonomy','term']
[permalinks.page]
s2 = "/c\\:d/:slug/"
-- content/s1/_index.md --
---
title: s1
url: "/a\\:b/:slug/"
---
-- content/s1/p1.md --
---
title: p1
url: "/a\\:b/:slug/"
---
-- content/s2/p2.md --
---
title: p2
---
-- layouts/single.html --
{{ .Title }}
-- layouts/list.html --
{{ .Title }}
`

	b := hugolib.Test(t, files)

	b.AssertFileExists("public/a:b/p1/index.html", true)
	b.AssertFileExists("public/a:b/s1/index.html", true)

	// The above URLs come from the URL front matter field where everything is allowed.
	// We strip colons from paths constructed by Hugo (they are not supported on Windows).
	b.AssertFileExists("public/cd/p2/index.html", true)
}

func TestPermalinksContentbasenameContentAdapter(t *testing.T) {
	t.Parallel()

	files := `
-- hugo.toml --
[permalinks]
[permalinks.page]
a = "/:slugorcontentbasename/"
b = "/:sections/:contentbasename/"
-- content/_content.gotmpl --
{{ $.AddPage  (dict "kind" "page" "path" "a/b/contentbasename1" "title" "My A Page No Slug")  }}
{{ $.AddPage (dict "kind" "page" "path" "a/b/contentbasename2" "slug" "myslug"  "title" "My A Page With Slug")  }}
 {{ $.AddPage  (dict "kind" "section" "path" "b/c" "title" "My B Section")  }}
{{ $.AddPage  (dict "kind" "page" "path" "b/c/contentbasename3" "title" "My B Page No Slug")  }}
-- layouts/single.html --
{{ .Title }}|{{ .RelPermalink }}|{{ .Kind }}|
`
	b := hugolib.Test(t, files)

	b.AssertFileContent("public/contentbasename1/index.html", "My A Page No Slug|/contentbasename1/|page|")
	b.AssertFileContent("public/myslug/index.html", "My A Page With Slug|/myslug/|page|")
}

func TestPermalinksContentbasenameWithAndWithoutFile(t *testing.T) {
	t.Parallel()

	files := `
-- hugo.toml --
[permalinks.section]
a = "/mya/:contentbasename/"
[permalinks.page]
a = "/myapage/:contentbasename/"
[permalinks.term]
categories = "/myc/:slugorcontentbasename/"
-- content/b/c/_index.md --
---
title: "C section"
---
-- content/a/b/index.md --
---
title: "My Title"
categories: ["c1", "c2"]
---
-- content/categories/c2/_index.md --
---
title: "C2"
slug: "c2slug"
---
-- layouts/single.html --
{{ .Title }}|{{ .RelPermalink }}|{{ .Kind }}|
-- layouts/list.html --
{{ .Title }}|{{ .RelPermalink }}|{{ .Kind }}|
`
	b := hugolib.Test(t, files)

	// Sections.
	b.AssertFileContent("public/mya/a/index.html", "As|/mya/a/|section|")

	// Pages.
	b.AssertFileContent("public/myapage/b/index.html", "My Title|/myapage/b/|page|")

	// Taxonomies.
	b.AssertFileContent("public/myc/c1/index.html", "C1|/myc/c1/|term|")
	b.AssertFileContent("public/myc/c2slug/index.html", "C2|/myc/c2slug/|term|")
}

func TestIssue13755(t *testing.T) {
	t.Parallel()

	files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
disablePathToLower = false
[permalinks.page]
s1 = "/:contentbasename"
-- content/s1/aBc.md --
---
title: aBc
---
-- layouts/all.html --
{{ .Title }}
`

	b := hugolib.Test(t, files)
	b.AssertFileExists("public/abc/index.html", true)

	files = strings.ReplaceAll(files, "disablePathToLower = false", "disablePathToLower = true")

	b = hugolib.Test(t, files)
	b.AssertFileExists("public/aBc/index.html", true)
}
