package hugolib

import (
	"fmt"
	"path/filepath"
	"strings"
	"testing"

	qt "github.com/frankban/quicktest"
	"github.com/gohugoio/hugo/common/paths"
	"github.com/gohugoio/hugo/resources/kinds"

	"github.com/spf13/afero"
)

func TestMultiSitesMainLangInRoot(t *testing.T) {
	files := `
-- hugo.toml --
defaultContentLanguage = "fr"
defaultContentLanguageInSubdir = false
disableKinds = ["taxonomy", "term"]
[languages]
[languages.en]
weight = 1
[languages.fr]
weight = 2
-- content/sect/doc1.en.md --
---
title: doc1 en
---
-- content/sect/doc1.fr.md --
---
title: doc1 fr
slug: doc1-fr
---
-- layouts/single.html --
Single: {{ .Title }}|{{ .Lang }}|{{ .RelPermalink }}|

`
	b := Test(t, files)
	b.AssertFileContent("public/sect/doc1-fr/index.html", "Single: doc1 fr|fr|/sect/doc1-fr/|")
	b.AssertFileContent("public/en/sect/doc1/index.html", "Single: doc1 en|en|/en/sect/doc1/|")
}

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

	files := `
-- hugo.toml --
defaultContentLanguage = "nn"

[languages]
[languages.nn]
label = "Nynorsk"
weight = 1
title = "Tittel på Nynorsk"
[languages.nn.params]
p1 = "p1nn"

[languages.en]
title = "Title in English"
label = "English"
weight = 2
[languages.en.params]
p1 = "p1en"
`
	b := Test(t, files, TestOptSkipRender())
	sites := b.H.Sites

	c := qt.New(t)
	c.Assert(len(sites), qt.Equals, 2)

	nnSite := sites[0]
	nnHome := nnSite.getPageOldVersion(kinds.KindHome)
	c.Assert(len(nnHome.AllTranslations()), qt.Equals, 2)
	c.Assert(len(nnHome.Translations()), qt.Equals, 1)
	c.Assert(nnHome.IsTranslated(), qt.Equals, true)

	enHome := sites[1].getPageOldVersion(kinds.KindHome)

	p1, err := enHome.Param("p1")
	c.Assert(err, qt.IsNil)
	c.Assert(p1, qt.Equals, "p1en")

	p1, err = nnHome.Param("p1")
	c.Assert(err, qt.IsNil)
	c.Assert(p1, qt.Equals, "p1nn")
}

func writeToFs(t testing.TB, fs afero.Fs, filename, content string) {
	t.Helper()
	if err := afero.WriteFile(fs, filepath.FromSlash(filename), []byte(content), 0o755); err != nil {
		t.Fatalf("Failed to write file: %s", err)
	}
}

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

	b := createBenchmarkAssembleDeepSiteWithManySectionsBuilder(t, false, 2, 3, 4).Build()
	b.AssertFileContent("public/index.html", "Num regular pages recursive: 48|")
}

func createBenchmarkAssembleDeepSiteWithManySectionsBuilder(t testing.TB, skipRender bool, sectionDepth, sectionsPerLevel, pagesPerSection int) *IntegrationTestBuilder {
	t.Helper()

	const contentTemplate = `---
title: P%d
---

## A title

Some content with a shortcode: {{< foo >}}.

Some more content and then another shortcode: {{< foo >}}.

Some final content.
`

	const filesTemplate = `
-- hugo.toml --
baseURL = "http://example.org/"
disableKinds = ["taxonomy", "term", "rss", "sitemap", "robotsTXT", "404"]
-- layouts/all.html --
All.{{ .Title }}|{{ .Content }}|Num pages: {{ len .Pages }}|Num sections: {{ len .Sections }}|Num regular pages recursive: {{ len .RegularPagesRecursive }}|
Sections: {{ range .Sections }}{{ .Title }}|{{ end }}|
RegularPagesRecursive: {{ range .RegularPagesRecursive }}{{ .RelPermalink }}|{{ end }}|
-- layouts/_shortcodes/foo.html --
`
	page := func(section string, i int) string {
		return fmt.Sprintf("\n-- content/%s/p%d.md --\n"+contentTemplate, section, i, i)
	}

	section := func(section string, i int) string {
		if section != "" {
			section = paths.AddTrailingSlash(section)
		}
		return fmt.Sprintf("\n-- content/%ss%d/_index.md --\n"+contentTemplate, section, i, i)
	}

	var sb strings.Builder

	// s0
	// s0/s0
	// s0/s1
	// etc.
	var (
		pageCount    int
		sectionCount int
	)
	var createSections func(currentSection string, currentDepth int)
	createSections = func(currentSection string, currentDepth int) {
		if currentDepth > sectionDepth {
			return
		}

		for i := range sectionsPerLevel {
			sectionCount++
			sectionName := fmt.Sprintf("s%d", i)
			sectionPath := sectionName
			if currentSection != "" {
				sectionPath = currentSection + "/" + sectionName
			}
			sb.WriteString(section(currentSection, i))

			// Pages in this section
			for j := range pagesPerSection {
				pageCount++
				sb.WriteString(page(sectionPath, j))
			}

			// Recurse
			createSections(sectionPath, currentDepth+1)
		}
	}

	createSections("", 1)

	sb.WriteString(filesTemplate)

	files := sb.String()

	return NewIntegrationTestBuilder(
		IntegrationTestConfig{
			T:           t,
			TxtarString: files,
			BuildCfg: BuildCfg{
				SkipRender: skipRender,
			},
		},
	)
}

func BenchmarkAssembleDeepSiteWithManySections(b *testing.B) {
	runOne := func(sectionDepth, sectionsPerLevel, pagesPerSection int) {
		name := fmt.Sprintf("depth=%d/sectionsPerLevel=%d/pagesPerSection=%d", sectionDepth, sectionsPerLevel, pagesPerSection)
		b.Run(name, func(b *testing.B) {
			for b.Loop() {
				b.StopTimer()
				bt := createBenchmarkAssembleDeepSiteWithManySectionsBuilder(b, true, sectionDepth, sectionsPerLevel, pagesPerSection)
				b.StartTimer()
				bt.Build()
			}
		})
	}

	runOne(1, 1, 50)
	runOne(1, 6, 100)
	runOne(1, 6, 500)
	runOne(2, 6, 100)
	runOne(4, 2, 100)
}
