package tmpls

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

// 核心：
// 1. 从嵌入的文件系统中读取指定目录下的单个配置文件内容
// 2. 检查文件是否存在
// 3. 读取文件内容
// 通配符说明:
//   - db/*/*.yaml : 匹配data/一级子目录下的所有yaml文件.
//   - 如需递归匹配子目录(如data/db/sub/*.yaml),用 data/**/*.yaml(Go.18+)
//
//go:embed services/*.yaml
var ConfigFS embed.FS

// GetConfigFile 获取指定目录下的的单个配置文件内容
//
// 参数:
//   - dir : 目录名(db/services/firewall...)
//   - name: 文件名(如base.yaml)
//
// 返回值:
//   - []byte: YAML 文件的内容
//   - error: 如果读取文件失败，返回错误信息
func GetConfigFile(dir, name string) ([]byte, error) {
	// 拼接完整路径(基于tmpls.go所在的 data 目录)
	fullPath := filepath.Join(dir, name)

	// 检查文件是否存在(避免ReadFile直接报错)
	_, err := fs.Stat(ConfigFS, fullPath)
	if err != nil {
		if errors.Is(err, fs.ErrNotExist) {
			return nil, fmt.Errorf("配置文件不存在: %s", fullPath)
		}
		return nil, fmt.Errorf("读取配置文件失败: %w", err)
	}

	// 读取文件内容
	content, err := ConfigFS.ReadFile(fullPath)
	if err != nil {
		return nil, fmt.Errorf("读取配置文件内容失败: %w", err)
	}

	return content, nil
}

// GetConfigDir 获取指定目录下的所有配置文件内容
//
// 参数:
//   - dir : 目录名(db/services/firewall...)
//
// 返回值:
//   - map[string][]byte: 键为文件名(如base.yaml), 值为文件内容
//   - error: 如果读取文件失败，返回错误信息
func GetConfigDir(dir string) (map[string][]byte, error) {
	// 存储结果: key=文件名 value=文件内容
	configMap := make(map[string][]byte)

	// 遍历指定目录下的所有文件
	err := fs.WalkDir(ConfigFS, dir,
		func(path string, d fs.DirEntry, err error) error {
			if err != nil {
				return fmt.Errorf("遍历目录失败: %w", err)
			}

			// 跳过目录，只处理文件
			if d.IsDir() {
				return nil
			}

			// 只处理yaml文件(双重效验，避免非yaml文件)
			if !strings.HasSuffix(d.Name(), ".yaml") {
				return nil
			}

			// 读取文件内容
			content, err := ConfigFS.ReadFile(path)
			if err != nil {
				return fmt.Errorf("读取文件内容失败: %w", err)
			}

			// 存储: key用文件名(如base.yaml),而非完整路径.
			configMap[d.Name()] = content
			return nil
		})
	if err != nil {
		return nil, err
	}

	return configMap, nil
}

// GetAllConfigDirs 获取所有嵌入目录(db/services/firewall...)的配置
//
// 返回值:
//   - map[目录名]map[文件名]文件内容
//   - error: 如果读取文件失败，返回错误信息
func GetAllConfigDirs() (map[string]map[string][]byte, error) {
	allConfigs := make(map[string]map[string][]byte)

	// 动态获取所有一级子目录(如db/services/firewall)
	dirs, err := GetAllSubDirs()
	if err != nil {
		return nil, err
	}

	// 遍历所有嵌入目录
	for _, dir := range dirs {
		dirConfigs, err := GetConfigDir(dir)
		if err != nil {
			// 可选: 忽略空目录、错误目录，继续处理其他目录
			// 如不需要、直接返回错误、return nil, err
			continue
		}
		allConfigs[dir] = dirConfigs
	}

	return allConfigs, nil
}

// GetAllSubDirs 动态获取data/下的所有一级子目录
//
// 返回值:
//   - []string: 所有一级子目录名(如db/services/firewall)
//   - error: 如果读取目录失败，返回错误信息
func GetAllSubDirs() ([]string, error) {
	var subDirs []string

	// 遍历data/目录下的所有一级子目录
	err := fs.WalkDir(ConfigFS, "",
		func(path string, d fs.DirEntry, err error) error {
			if err != nil {
				return fmt.Errorf("遍历目录失败: %w", err)
			}

			// 过滤条件:
			// 1. 是目录(d.IsDir())
			// 2. 是一级子目录(path不含/,排除嵌套子目录如db/sub)
			// 3. 排除根目录本身(path != "")
			if d.IsDir() && !strings.Contains(path, "/") && path != "" {
				subDirs = append(subDirs, path)
				// 跳过该目录的子目录遍历(提升性能)
				return fs.SkipDir
			}
			return nil
		})

	if err != nil {
		return nil, err
	}

	return subDirs, nil
}
