package cms

import (
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"strings"
)

func CreateMenu(root, name string) (string, error) {
	name = slugify(name)
	if name == "" || name == "untitled" {
		return "", fmt.Errorf("menu name is required")
	}
	path := filepath.Join(root, "site/menus", name+".toml")
	data := "name = " + formatString(name) + "\n\n"
	return path, writeNewFile(path, []byte(data))
}

func LoadMenus(root string) (map[string]Menu, error) {
	dir := filepath.Join(root, "site/menus")
	menus := map[string]Menu{}
	if _, err := os.Stat(dir); err != nil {
		if os.IsNotExist(err) {
			return menus, nil
		}
		return nil, err
	}
	err := filepath.WalkDir(dir, func(path string, entry fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		if entry.IsDir() || filepath.Ext(path) != ".toml" {
			return nil
		}
		menu, err := loadMenu(path)
		if err != nil {
			return err
		}
		menus[menu.Name] = menu
		return nil
	})
	return menus, err
}

func AddMenuItem(root string, opts MenuItemOptions) error {
	name := slugify(opts.Menu)
	if name == "" || name == "untitled" {
		return fmt.Errorf("menu name is required")
	}
	path := filepath.Join(root, "site/menus", name+".toml")
	menu, err := loadMenu(path)
	if err != nil {
		if os.IsNotExist(err) {
			if _, createErr := CreateMenu(root, name); createErr != nil {
				return createErr
			}
			menu = Menu{Name: name}
		} else {
			return err
		}
	}
	item, err := resolveMenuItem(opts)
	if err != nil {
		return err
	}
	menu.Items = append(menu.Items, item)
	return saveMenu(path, menu)
}

func loadMenu(path string) (Menu, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return Menu{}, err
	}
	menu := Menu{Name: strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))}
	var current *MenuItem

	for lineNo, raw := range strings.Split(string(data), "\n") {
		line := strings.TrimSpace(raw)
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		if line == "[[items]]" {
			menu.Items = append(menu.Items, MenuItem{})
			current = &menu.Items[len(menu.Items)-1]
			continue
		}
		key, rawValue, ok := strings.Cut(line, "=")
		if !ok {
			return Menu{}, fmt.Errorf("%s:%d: expected key = value", path, lineNo+1)
		}
		value, err := parseScalar(strings.TrimSpace(rawValue))
		if err != nil {
			return Menu{}, fmt.Errorf("%s:%d: %w", path, lineNo+1, err)
		}
		key = strings.TrimSpace(key)
		if current == nil {
			if key == "name" {
				menu.Name = value
			}
			continue
		}
		switch key {
		case "label":
			current.Label = value
		case "url":
			current.URL = value
		}
	}
	if menu.Name == "" {
		menu.Name = strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))
	}
	return menu, nil
}

func saveMenu(path string, menu Menu) error {
	var b strings.Builder
	b.WriteString("name = " + formatString(menu.Name) + "\n")
	for _, item := range menu.Items {
		b.WriteString("\n[[items]]\n")
		b.WriteString("label = " + formatString(item.Label) + "\n")
		b.WriteString("url = " + formatString(item.URL) + "\n")
	}
	return writeFile(path, []byte(b.String()))
}

func resolveMenuItem(opts MenuItemOptions) (MenuItem, error) {
	label := opts.Label
	url := opts.URL
	target := slugify(opts.Target)

	switch opts.Kind {
	case "home":
		if label == "" {
			label = "Home"
		}
		if url == "" {
			url = "/"
		}
	case "page":
		if target == "" || target == "untitled" {
			return MenuItem{}, fmt.Errorf("page menu item requires a target")
		}
		if label == "" {
			label = titleize(target)
		}
		if url == "" {
			if target == "index" {
				url = "/"
			} else {
				url = "/" + target + ".gmi"
			}
		}
	case "section":
		if target == "" || target == "untitled" {
			return MenuItem{}, fmt.Errorf("section menu item requires a target")
		}
		if label == "" {
			label = titleize(target)
		}
		if url == "" {
			url = "/" + target + "/"
		}
	case "article":
		if target == "" || target == "untitled" {
			return MenuItem{}, fmt.Errorf("article menu item requires a target")
		}
		if label == "" {
			label = titleize(target)
		}
		if url == "" {
			url = "/articles/" + target + ".gmi"
		}
	case "custom":
		if label == "" {
			label = titleize(target)
		}
		if url == "" {
			return MenuItem{}, fmt.Errorf("custom menu item requires --url")
		}
	default:
		if label == "" {
			label = titleize(opts.Kind)
		}
		if url == "" {
			url = "/" + slugify(opts.Kind) + ".gmi"
		}
	}

	return MenuItem{Label: label, URL: url}, nil
}
