package presets

import (
	"bytes"
	"embed"
	"errors"
	"fmt"
	"io/fs"
	"path"
	"sort"
	"strings"
	"text/template"

	"gopkg.in/yaml.v3"
)

// SkillScaffoldFile is one file emitted by the skill repository scaffold
// preset. Content has already been locale-resolved and template-substituted.
type SkillScaffoldFile struct {
	Path    string
	Content string
}

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

//go:embed assets/skills/scaffold
var skillScaffoldFS embed.FS

const (
	skillScaffoldRoot       = "assets/skills/scaffold"
	skillScaffoldMetaFile   = "assets/skills/scaffold/meta.yaml"
	skillScaffoldReadmeName = "README.md"
)

// SkillScaffoldFiles returns the per-locale scaffold files for a new skill
// repository, with the README header templated against the user-supplied
// name and description.
func SkillScaffoldFiles(name, description, locale string) ([]SkillScaffoldFile, error) {
	resolved := NormalizeLocale(locale)
	dir := localeDir(resolved)
	root := path.Join(skillScaffoldRoot, dir)
	files := map[string][]byte{}
	err := fs.WalkDir(skillScaffoldFS, root, func(p string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		if d.IsDir() {
			return nil
		}
		content, err := skillScaffoldFS.ReadFile(p)
		if err != nil {
			return err
		}
		rel := strings.TrimPrefix(p, root+"/")
		if rel == "" {
			return nil
		}
		files[rel] = content
		return nil
	})
	if err != nil {
		return nil, fmt.Errorf("read skill scaffold %q: %w", resolved, err)
	}
	if len(files) == 0 {
		return nil, errors.New("skill scaffold not embedded for locale " + resolved)
	}
	out := make([]SkillScaffoldFile, 0, len(files))
	for rel, content := range files {
		rendered, err := renderScaffoldFile(rel, content, name, description)
		if err != nil {
			return nil, err
		}
		out = append(out, SkillScaffoldFile{Path: rel, Content: rendered})
	}
	sort.Slice(out, func(i, j int) bool { return out[i].Path < out[j].Path })
	return out, nil
}

// SkillScaffoldInitialCommitMessage returns the localized initial commit
// message for a new skill repository.
func SkillScaffoldInitialCommitMessage(locale string) string {
	resolved := NormalizeLocale(locale)
	meta := loadSkillScaffoldMeta()
	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 skill repository"
}

func loadSkillScaffoldMeta() scaffoldPresetMeta {
	raw, err := skillScaffoldFS.ReadFile(skillScaffoldMetaFile)
	if err != nil {
		return scaffoldPresetMeta{}
	}
	var meta scaffoldPresetMeta
	if err := yaml.Unmarshal(raw, &meta); err != nil {
		return scaffoldPresetMeta{}
	}
	return meta
}

func renderScaffoldFile(rel string, content []byte, name, description string) (string, error) {
	if path.Base(rel) != skillScaffoldReadmeName {
		return string(content), nil
	}
	tmpl, err := template.New("scaffold").Parse(string(content))
	if err != nil {
		return "", fmt.Errorf("parse scaffold template %q: %w", rel, err)
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, map[string]string{
		"Name":        name,
		"Description": description,
	}); err != nil {
		return "", fmt.Errorf("execute scaffold template %q: %w", rel, err)
	}
	return buf.String(), nil
}
