package presets

import (
	"embed"
	"errors"
	"fmt"
	"io/fs"
	"path"
	"path/filepath"
	"sort"
	"strings"

	"gopkg.in/yaml.v3"
)

// MemoryTemplateFile is one file in the memory repository preset.
type MemoryTemplateFile struct {
	Path    string
	Content []byte
}

// MemoryLabel describes a locale-specific label that should exist in a
// memory repository.
type MemoryLabel struct {
	Key         string
	Name        string
	Color       string
	Description string
}

type memoryPresetMeta struct {
	InitialCommitMessage map[string]string `yaml:"initial_commit_message"`
}

type memoryLabelDefinition struct {
	Key         string            `yaml:"key"`
	Color       string            `yaml:"color"`
	Name        map[string]string `yaml:"name"`
	Description map[string]string `yaml:"description"`
}

type memoryLabelsFile struct {
	Labels []memoryLabelDefinition `yaml:"labels"`
}

//go:embed assets/memory/standard
var memoryPresetFS embed.FS

const (
	memoryPresetRoot      = "assets/memory/standard"
	memoryPresetMetaFile  = "assets/memory/standard/meta.yaml"
	memoryPresetLabelsFile = "assets/memory/standard/labels.yaml"
)

// MemoryTemplateFiles returns the per-locale template files for the memory
// repository preset. Locale is normalized via NormalizeLocale.
func MemoryTemplateFiles(locale string) ([]MemoryTemplateFile, error) {
	root := path.Join(memoryPresetRoot, localeDir(locale))
	var files []MemoryTemplateFile
	err := fs.WalkDir(memoryPresetFS, root, func(p string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		if d.IsDir() {
			return nil
		}
		content, err := memoryPresetFS.ReadFile(p)
		if err != nil {
			return err
		}
		rel, err := filepath.Rel(root, p)
		if err != nil {
			return err
		}
		rel = filepath.ToSlash(rel)
		if rel == "." || strings.TrimSpace(rel) == "" {
			return nil
		}
		files = append(files, MemoryTemplateFile{Path: rel, Content: content})
		return nil
	})
	if err != nil {
		return nil, fmt.Errorf("read memory preset %q: %w", locale, err)
	}
	sort.Slice(files, func(i, j int) bool { return files[i].Path < files[j].Path })
	return files, nil
}

// MemoryLabels returns the locale-specific label taxonomy for the memory
// repository preset.
func MemoryLabels(locale string) []MemoryLabel {
	resolved := NormalizeLocale(locale)
	defs := loadMemoryLabelDefinitions()
	labels := make([]MemoryLabel, 0, len(defs))
	for _, def := range defs {
		labels = append(labels, MemoryLabel{
			Key:         def.Key,
			Color:       def.Color,
			Name:        pickLocale(def.Name, resolved),
			Description: pickLocale(def.Description, resolved),
		})
	}
	return labels
}

// MemoryInitialCommitMessage returns the localized initial commit message
// for the memory repository preset.
func MemoryInitialCommitMessage(locale string) string {
	resolved := NormalizeLocale(locale)
	meta := loadMemoryPresetMeta()
	if msg, ok := meta.InitialCommitMessage[resolved]; ok && strings.TrimSpace(msg) != "" {
		return msg
	}
	if msg, ok := meta.InitialCommitMessage[LocaleEnglish]; ok && strings.TrimSpace(msg) != "" {
		return msg
	}
	return "Initialize memory repository"
}

func loadMemoryPresetMeta() memoryPresetMeta {
	raw, err := memoryPresetFS.ReadFile(memoryPresetMetaFile)
	if err != nil {
		return memoryPresetMeta{}
	}
	var meta memoryPresetMeta
	if err := yaml.Unmarshal(raw, &meta); err != nil {
		return memoryPresetMeta{}
	}
	return meta
}

func loadMemoryLabelDefinitions() []memoryLabelDefinition {
	raw, err := memoryPresetFS.ReadFile(memoryPresetLabelsFile)
	if err != nil {
		return nil
	}
	var file memoryLabelsFile
	if err := yaml.Unmarshal(raw, &file); err != nil {
		return nil
	}
	return file.Labels
}

func pickLocale(values map[string]string, locale string) string {
	if v, ok := values[locale]; ok && strings.TrimSpace(v) != "" {
		return v
	}
	if v, ok := values[LocaleEnglish]; ok && strings.TrimSpace(v) != "" {
		return v
	}
	for _, v := range values {
		return v
	}
	return ""
}

// MemoryLabelDefinitionsRaw is exported for tests that need to validate the
// underlying label taxonomy without locale normalization.
func MemoryLabelDefinitionsRaw() ([]MemoryLabel, error) {
	defs := loadMemoryLabelDefinitions()
	if defs == nil {
		return nil, errors.New("memory preset labels not embedded")
	}
	out := make([]MemoryLabel, 0, len(defs))
	for _, def := range defs {
		out = append(out, MemoryLabel{
			Key:         def.Key,
			Color:       def.Color,
			Name:        pickLocale(def.Name, LocaleEnglish),
			Description: pickLocale(def.Description, LocaleEnglish),
		})
	}
	return out, nil
}
