// Package config provides centralized path management for the fetch_ml project.
package config

import (
	"os"
	"path/filepath"
)

// PathRegistry provides centralized path management
type PathRegistry struct {
	RootDir string // Repository root (auto-detected or from env)
}

// NewPathRegistry creates a path registry from root directory.
// If root is empty, attempts to auto-detect repository root.
func NewPathRegistry(root string) *PathRegistry {
	if root == "" {
		root = detectRepoRoot()
	}
	return &PathRegistry{RootDir: root}
}

// Binary paths
func (p *PathRegistry) BinDir() string            { return filepath.Join(p.RootDir, "bin") }
func (p *PathRegistry) APIServerBinary() string   { return filepath.Join(p.BinDir(), "api-server") }
func (p *PathRegistry) WorkerBinary() string      { return filepath.Join(p.BinDir(), "worker") }
func (p *PathRegistry) TUIBinary() string         { return filepath.Join(p.BinDir(), "tui") }
func (p *PathRegistry) DataManagerBinary() string { return filepath.Join(p.BinDir(), "data_manager") }

// Data paths
func (p *PathRegistry) DataDir() string       { return filepath.Join(p.RootDir, "data") }
func (p *PathRegistry) ActiveDataDir() string { return filepath.Join(p.DataDir(), "active") }
func (p *PathRegistry) JupyterStateDir() string {
	return filepath.Join(p.DataDir(), "active", "jupyter")
}
func (p *PathRegistry) ExperimentsDir() string { return filepath.Join(p.DataDir(), "experiments") }
func (p *PathRegistry) ProdSmokeDir() string   { return filepath.Join(p.DataDir(), "prod-smoke") }

// Database paths
func (p *PathRegistry) DBDir() string      { return filepath.Join(p.RootDir, "db") }
func (p *PathRegistry) SQLitePath() string { return filepath.Join(p.DBDir(), "fetch_ml.db") }

// Log paths
func (p *PathRegistry) LogDir() string       { return filepath.Join(p.RootDir, "logs") }
func (p *PathRegistry) AuditLogPath() string { return filepath.Join(p.LogDir(), "fetchml-audit.log") }

// Config paths
func (p *PathRegistry) ConfigDir() string { return filepath.Join(p.RootDir, "configs") }
func (p *PathRegistry) APIServerConfig() string {
	return filepath.Join(p.ConfigDir(), "api", "dev.yaml")
}
func (p *PathRegistry) WorkerConfigDir() string { return filepath.Join(p.ConfigDir(), "workers") }

// Test paths
func (p *PathRegistry) TestResultsDir() string { return filepath.Join(p.RootDir, "test_results") }
func (p *PathRegistry) TempDir() string        { return filepath.Join(p.RootDir, "tmp") }

// State file paths (for service persistence)
func (p *PathRegistry) JupyterServicesFile() string {
	return filepath.Join(p.JupyterStateDir(), "fetch_ml_jupyter_services.json")
}

func (p *PathRegistry) JupyterWorkspacesFile() string {
	return filepath.Join(p.JupyterStateDir(), "fetch_ml_jupyter_workspaces.json")
}

// EnsureDir creates directory if it doesn't exist with appropriate permissions.
func (p *PathRegistry) EnsureDir(path string) error {
	return os.MkdirAll(path, 0750)
}

// EnsureDirSecure creates directory with restricted permissions (for sensitive data).
func (p *PathRegistry) EnsureDirSecure(path string) error {
	return os.MkdirAll(path, 0700)
}

// FileExists checks if a file exists.
func (p *PathRegistry) FileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

// detectRepoRoot finds repository root by looking for go.mod.
// Returns current directory if not found.
func detectRepoRoot() string {
	dir, err := os.Getwd()
	if err != nil {
		return "."
	}

	// Walk up directory tree looking for go.mod
	for {
		if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
			return dir
		}

		parent := filepath.Dir(dir)
		if parent == dir {
			// Reached root
			break
		}
		dir = parent
	}

	return "."
}

// FromEnv creates PathRegistry with root from FETCHML_ROOT env var,
// or auto-detects if env var not set.
func FromEnv() *PathRegistry {
	root := os.Getenv("FETCHML_ROOT")
	return NewPathRegistry(root)
}
