package io

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/acepanel/panel/pkg/shell"
)

// Search 查找文件/文件夹
func Search(path, keyword string, sub bool) (map[string]os.FileInfo, error) {
	paths := make(map[string]os.FileInfo)
	baseDepth := strings.Count(filepath.Clean(path), string(os.PathSeparator))

	err := filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !sub && strings.Count(p, string(os.PathSeparator)) > baseDepth+1 {
			return filepath.SkipDir
		}
		if strings.Contains(info.Name(), keyword) {
			paths[p] = info
		}
		return nil
	})

	return paths, err
}

// SearchX 查找文件/文件夹（find命令）
func SearchX(path, keyword string, sub bool) ([]os.DirEntry, error) {
	var out string
	var err error
	if sub {
		out, err = shell.Execf("find '%s' -name '*%s*'", path, keyword)
	} else {
		out, err = shell.Execf("find '%s' -maxdepth 1 -name '*%s*'", path, keyword)
	}
	if err != nil {
		return nil, err
	}

	var entries []os.DirEntry
	lines := strings.Split(out, "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" || line == path {
			continue
		}
		entry, err := newSearchEntryFromPath(line)
		if err != nil {
			continue // 直接跳过，不返回错误，不然很烦人的
		}
		entries = append(entries, entry)
	}

	return entries, nil
}

// SearchEntry 实现 os.DirEntry 接口
type SearchEntry struct {
	path string
	info os.FileInfo
}

// newSearchEntryFromPath 根据文件路径创建 SearchEntry
func newSearchEntryFromPath(path string) (*SearchEntry, error) {
	info, err := os.Lstat(path) // 不跟随符号链接
	if err != nil {
		return nil, err
	}
	return &SearchEntry{path: path, info: info}, nil
}

// Name 返回文件基本名称
func (d *SearchEntry) Name() string {
	return filepath.Base(d.path)
}

// IsDir 判断是否为目录
func (d *SearchEntry) IsDir() bool {
	return d.info.IsDir()
}

// Type 返回文件模式类型
func (d *SearchEntry) Type() os.FileMode {
	return d.info.Mode().Type()
}

// Info 返回文件信息
func (d *SearchEntry) Info() (os.FileInfo, error) {
	return d.info, nil
}

// Path 返回文件完整路径
func (d *SearchEntry) Path() string {
	return d.path
}
