package wikipress

import (
	"embed"
	"fmt"
	"html/template"
	"os"
	"sort"
	"strings"

	"github.com/google/uuid"
)

func CreateFilePageAndCopyContent(file File, outfolder string) error {
	if file.GetExtension() == "md" {
		return nil
	}

	for versionNumber := range file.Versions {
		folder := fmt.Sprintf("%v/%v", outfolder, file.GetFolder())
		path := fmt.Sprintf("%v/%v_%v.%v", folder, file.GetName(), file.Versions[versionNumber].Hash, file.GetExtension())
		err := os.WriteFile(path, file.Versions[versionNumber].contentbinary, 0o644)
		if err != nil {
			return err
		}
	}

	return nil
}

func GenerateHTMLPageForMarkedown(file File, menu MenuItem, outfolder string, layout embed.FS) error {
	os.MkdirAll(outfolder, 0755)
	if file.GetExtension() != "md" {
		return ErrCantRenderNonMarktdownFile
	}

	for versionnumber := range file.Versions {
		err := renderHTML(file, menu, versionnumber, outfolder, layout)
		if err != nil {
			return err
		}
	}

	return nil
}

type MenuItem struct {
	ID       string
	Name     string
	Text     string
	Link     string
	File     File
	Level    int
	Children []*MenuItem
	Page     bool
}

func GenerateMenu(files []File) MenuItem {
	menu := MenuItem{}
	for _, file := range files {
		if file.Deleted {
			continue
		}
		if file.GetExtension() != "md" {
			continue
		}
		folders := file.GetFolders()
		folders = append(folders, "")
		currentMenu := &menu
		for level, folderLevel := range folders {
			if folderLevel == "" {
				newMenuItem := MenuItem{}
				newMenuItem.Name = file.GetTitle()
				newMenuItem.Page = true
				newMenuItem.File = file
				newMenuItem.Level = level
				if file.GetFolder() != "" {
					newMenuItem.Link = "/" + file.GetFolder()
				}
				newMenuItem.Link = newMenuItem.Link + "/" + file.GetName() + ".html"
				currentMenu.Children = append(currentMenu.Children, &newMenuItem)
				break
				// Create new Item
			} else {
				found := false
				for _, m := range currentMenu.Children {
					if m.Name == folderLevel {
						currentMenu = m
						found = true
					}
				}
				if !found {
					newMenuItem := MenuItem{}
					newMenuItem.ID = uuid.NewString()
					newMenuItem.Name = folderLevel
					newMenuItem.Level = level
					newMenuItem.Text = strings.Title(folderLevel)
					currentMenu.Children = append(currentMenu.Children, &newMenuItem)
					currentMenu = &newMenuItem
				}
				// Get children or create a new one if needed
			}
		}
	}
	menu.Children = sortMenu(menu.Children)
	return menu
}

func sortMenu(input []*MenuItem) []*MenuItem {
	sort.Slice(input, func(i, j int) bool {
		return strings.ToLower(input[i].Name) < strings.ToLower(input[j].Name)
	})

	sort.Slice(input, func(i, j int) bool {
		if input[i].File.GetMenuPosition() < input[j].File.GetMenuPosition() {
			return true
		}
		return false
	})

	for _, i := range input {
		i.Children = sortMenu(i.Children)
	}

	return input
}

type htmlTemplateData struct {
	HTMLContent template.HTML
	Title       string
	File        File
	Menu        MenuItem
	Folders     []string
	Version     Version
}

func renderHTML(file File, menu MenuItem, versionNumber int, outfolder string, layout embed.FS) error {
	folder := fmt.Sprintf("%v/%v", outfolder, file.GetFolder())
	htmlPath := fmt.Sprintf("%v/%v_%v.html", folder, file.GetName(), file.Versions[versionNumber].Hash)
	fmt.Println(htmlPath)
	os.MkdirAll(folder, 0755)

	var err error
	h := htmlTemplateData{}
	h.Menu = menu
	h.Title = file.Versions[versionNumber].GetHeader("title", file.GetName())
	h.File = file
	h.Folders = file.GetFolders()
	h.Version = file.Versions[versionNumber]
	content, err := file.Versions[versionNumber].GetHTMLContent()
	if err != nil {
		return err
	}
	h.HTMLContent = template.HTML(content)

	tmpl := template.New("default.html")

	tmpl.Funcs(template.FuncMap{
		"dict":  dict,
		"index": index,
	})

	tmpl, err = tmpl.ParseFS(layout, "layout/src/default.html")
	if err != nil {
		return err
	}

	outFile, err := os.Create(htmlPath)
	if err != nil {
		return err
	}

	err = tmpl.Execute(outFile, h)
	if err != nil {
		return err
	}

	return nil
}

func dict(values ...any) map[string]any {
	m := make(map[string]any)
	for i := 0; i < len(values); i += 2 {
		m[values[i].(string)] = values[i+1]
	}
	return m
}

func index(slice []string, i int) string {
	if i < 0 || i >= len(slice) {
		return ""
	}
	return slice[i]
}
