package utils

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

// FindFilesOptions configures directory scanning
type FindFilesOptions struct {
	Extension    string   // e.g. ".wav" or ".data"
	Recursive    bool     // whether to walk subdirectories
	SkipPrefixes []string // directory prefixes to skip (e.g. "Clips_")
	SkipHidden   bool     // skip files/folders starting with "."
	MinSize      int64    // minimum file size in bytes
}

// FindFiles scans a directory for files matching the given options
func FindFiles(rootPath string, opts FindFilesOptions) ([]string, error) {
	var results []string

	if opts.Recursive {
		if err := filepath.Walk(rootPath, makeWalkFunc(&results, opts, rootPath)); err != nil {
			return nil, err
		}
	} else {
		if err := scanFlatDir(rootPath, &results, opts); err != nil {
			return nil, err
		}
	}

	sort.Strings(results)
	return results, nil
}

// makeWalkFunc returns a filepath.WalkFunc that collects matching files.
func makeWalkFunc(results *[]string, opts FindFilesOptions, rootPath string) filepath.WalkFunc {
	return func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		name := info.Name()

		// Skip hidden files/directories
		if opts.SkipHidden && strings.HasPrefix(name, ".") && path != rootPath {
			if info.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}

		// Check directory skip prefixes
		if info.IsDir() && path != rootPath {
			for _, prefix := range opts.SkipPrefixes {
				if strings.HasPrefix(name, prefix) {
					return filepath.SkipDir
				}
			}
			return nil
		}

		// Check file
		if !info.IsDir() {
			if fileMatches(name, info, opts) {
				*results = append(*results, path)
			}
		}

		return nil
	}
}

// fileMatches checks if a file name meets the extension and size criteria.
func fileMatches(name string, info os.FileInfo, opts FindFilesOptions) bool {
	if !strings.EqualFold(filepath.Ext(name), opts.Extension) {
		return false
	}
	if info.Size() < opts.MinSize {
		return false
	}
	return true
}

// scanFlatDir scans a single directory level for matching files.
func scanFlatDir(rootPath string, results *[]string, opts FindFilesOptions) error {
	entries, err := os.ReadDir(rootPath)
	if err != nil {
		return err
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		name := entry.Name()
		if opts.SkipHidden && strings.HasPrefix(name, ".") {
			continue
		}
		if !strings.EqualFold(filepath.Ext(name), opts.Extension) {
			continue
		}
		path := filepath.Join(rootPath, name)
		if info, err := os.Stat(path); err == nil && info.Size() >= opts.MinSize {
			*results = append(*results, path)
		}
	}
	return nil
}