package booker

import (
	"encoding/json"
	"gardening/src/lib"
	"gardening/src/lib/config"
	"gitlab.com/ccyrillee/kitcla/goc"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

type Booker struct {
	Config *config.Config
}

func (this *Booker) AddPage(name string, h goc.HTML) {
	filePath := this.testFilePath()
	println(filePath)

	ss := strings.Split(filePath, "/")
	componentName := strings.TrimSuffix(ss[len(ss)-1], "_test.go")
	subKind := ss[len(ss)-2]
	kind := ss[len(ss)-3]

	htmlContent := goc.RenderRoot(h)
	htmlContent = "<!DOCTYPE html>\n" + htmlContent
	htmlContent = this.indentHTML(htmlContent)

	rootDir := this.Config.GetRootDir()
	fileName := this.toSnakeCase(name)
	htmlFilePath := filepath.Join(rootDir, "docs", "pages", kind, subKind, componentName, fileName+".html")
	jsonFilePath := filepath.Join(rootDir, "docs", "pages", kind, subKind, componentName, fileName+".json")
	basePath := filepath.Dir(htmlFilePath)
	err := os.MkdirAll(basePath, 0777)
	lib.Poe(err)
	err = os.WriteFile(htmlFilePath, []byte(htmlContent), 0644)
	lib.Poe(err)
	s := struct {
		Name          string
		ComponentName string
		Kind          string
		SubKind       string
		TestFilePath  string
		HtmlFilePath  string
	}{
		Name:          name,
		ComponentName: componentName,
		Kind:          kind,
		SubKind:       subKind,
		TestFilePath:  strings.TrimPrefix(filePath, rootDir),
		HtmlFilePath:  strings.TrimPrefix(htmlFilePath, rootDir),
	}
	b, err := json.Marshal(s)
	err = os.WriteFile(jsonFilePath, b, 0644)
	lib.Poe(err)
}

func (this *Booker) testFilePath() string {
	for skip := 0; ; skip++ {
		_, file, _, ok := runtime.Caller(skip)
		if !ok {
			break
		}
		if strings.Count(file, "/tests/") > 0 {
			return file
		}
	}
	panic("Unable to detect test file path")
}

func (this *Booker) toSnakeCase(s string) string {
	re := regexp.MustCompile("([a-z0-9])([A-Z])")
	snake := re.ReplaceAllString(s, "${1}_${2}")
	snake = strings.ToLower(snake)
	return snake
}

func (this *Booker) indentHTML(htmlContent string) string {
	htmlContent = this.addLineBreaks(htmlContent)
	lines := strings.Split(htmlContent, "\n")
	var result []string
	indentLevel := 0

	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if trimmed == "" {
			result = append(result, "")
			continue
		}

		if strings.HasPrefix(trimmed, "</") {
			indentLevel--
			if indentLevel < 0 {
				indentLevel = 0
			}
		}

		indent := strings.Repeat("  ", indentLevel)
		result = append(result, indent+trimmed)

		if strings.HasPrefix(trimmed, "<") && !strings.HasPrefix(trimmed, "</") && !strings.HasSuffix(trimmed, "/>") {
			indentLevel++
		}
	}

	return strings.Join(result, "\n")
}

func (this *Booker) addLineBreaks(html string) string {
	html = strings.ReplaceAll(html, "><", ">\n<")
	return html
}
