package skill

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/sdaduanbilei/agent-team/internal/llm"
	"gopkg.in/yaml.v3"
)

type Meta struct {
	Name        string `yaml:"name"`
	Description string `yaml:"description"`
	Path        string `yaml:"-"`
}

type Skill struct {
	Meta
	Body string // full SKILL.md body (instructions)
}

// Discover 递归扫描 skillsDir，返回所有包含 SKILL.md 的目录的元数据。
func Discover(skillsDir string) ([]Meta, error) {
	var metas []Meta
	filepath.Walk(skillsDir, func(path string, info os.FileInfo, err error) error {
		if err != nil || info.IsDir() || info.Name() != "SKILL.md" {
			return nil
		}
		data, err := os.ReadFile(path)
		if err != nil {
			return nil
		}
		meta, err := ParseMeta(data)
		if err != nil {
			return nil
		}
		meta.Path = filepath.Dir(path)
		metas = append(metas, meta)
		return nil
	})
	return metas, nil
}

// Load returns a fully loaded skill including body.
func Load(skillDir string) (*Skill, error) {
	data, err := os.ReadFile(filepath.Join(skillDir, "SKILL.md"))
	if err != nil {
		return nil, err
	}
	meta, err := ParseMeta(data)
	if err != nil {
		return nil, err
	}
	meta.Path = skillDir
	body := extractBody(data)
	return &Skill{Meta: meta, Body: body}, nil
}

// ToXML generates <available_skills> XML for agent system prompts.
// 如果 skill 有完整内容，会注入到 prompt 中。
func ToXML(metas []Meta) string {
	var sb strings.Builder
	sb.WriteString("<available_skills>\n")
	for _, m := range metas {
		// 尝试加载完整 skill 内容
		s, err := Load(m.Path)
		if err == nil && s.Body != "" {
			fmt.Fprintf(&sb, "  <skill name=\"%s\">\n    <description>%s</description>\n    <instructions>\n%s\n    </instructions>\n  </skill>\n",
				m.Name, m.Description, s.Body)
		} else {
			fmt.Fprintf(&sb, "  <skill name=\"%s\">\n    <description>%s</description>\n  </skill>\n",
				m.Name, m.Description)
		}
	}
	sb.WriteString("</available_skills>")
	return sb.String()
}

func ParseMeta(data []byte) (Meta, error) {
	var meta Meta
	if !bytes.HasPrefix(data, []byte("---")) {
		return meta, fmt.Errorf("missing frontmatter")
	}
	parts := bytes.SplitN(data, []byte("---"), 3)
	if len(parts) < 3 {
		return meta, fmt.Errorf("invalid frontmatter")
	}
	return meta, yaml.Unmarshal(parts[1], &meta)
}

func extractBody(data []byte) string {
	parts := bytes.SplitN(data, []byte("---"), 3)
	if len(parts) < 3 {
		return string(data)
	}
	return strings.TrimSpace(string(parts[2]))
}

// ToTools 将 skill 列表转为 LLM tool 定义。
// 每个有 scripts/ 目录的 skill 生成一个 tool。
func ToTools(metas []Meta) []llm.Tool {
	var tools []llm.Tool
	for _, m := range metas {
		scriptsDir := filepath.Join(m.Path, "scripts")
		if _, err := os.Stat(scriptsDir); err != nil {
			continue // 没有 scripts 目录的 skill 不注册为 tool
		}
		tools = append(tools, llm.Tool{
			Type: llm.ToolTypeFunction,
			Function: &llm.FunctionDefinition{
				Name:        "skill_" + strings.ReplaceAll(m.Name, "-", "_"),
				Description: m.Description,
				Parameters: json.RawMessage(`{
					"type": "object",
					"properties": {
						"command": {
							"type": "string",
							"description": "要执行的完整 bash 命令，例如: bash \"$SKILLS_ROOT/` + m.Name + `/scripts/search.sh\" \"搜索关键词\" 5"
						}
					},
					"required": ["command"]
				}`),
			},
		})
	}
	return tools
}

// SkillPathByToolName 根据 tool 函数名找到对应 skill 的路径
func SkillPathByToolName(metas []Meta, funcName string) string {
	for _, m := range metas {
		toolName := "skill_" + strings.ReplaceAll(m.Name, "-", "_")
		if toolName == funcName {
			return m.Path
		}
	}
	return ""
}
