package agentic

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

	errors "github.com/host-uk/core/pkg/framework/core"
	"github.com/host-uk/core/pkg/io"
	"gopkg.in/yaml.v3"
)

// Config holds the configuration for connecting to the core-agentic service.
type Config struct {
	// BaseURL is the URL of the core-agentic API server.
	BaseURL string `yaml:"base_url" json:"base_url"`
	// Token is the authentication token for API requests.
	Token string `yaml:"token" json:"token"`
	// DefaultProject is the project to use when none is specified.
	DefaultProject string `yaml:"default_project" json:"default_project"`
	// AgentID is the identifier for this agent (optional, used for claiming tasks).
	AgentID string `yaml:"agent_id" json:"agent_id"`
}

// configFileName is the name of the YAML config file.
const configFileName = "agentic.yaml"

// envFileName is the name of the environment file.
const envFileName = ".env"

// DefaultBaseURL is the default API endpoint if none is configured.
const DefaultBaseURL = "https://api.core-agentic.dev"

// LoadConfig loads the agentic configuration from the specified directory.
// It first checks for a .env file, then falls back to ~/.core/agentic.yaml.
// If dir is empty, it checks the current directory first.
//
// Environment variables take precedence:
//   - AGENTIC_BASE_URL: API base URL
//   - AGENTIC_TOKEN: Authentication token
//   - AGENTIC_PROJECT: Default project
//   - AGENTIC_AGENT_ID: Agent identifier
func LoadConfig(dir string) (*Config, error) {
	cfg := &Config{
		BaseURL: DefaultBaseURL,
	}

	// Try loading from .env file in the specified directory
	if dir != "" {
		envPath := filepath.Join(dir, envFileName)
		if err := loadEnvFile(envPath, cfg); err == nil {
			// Successfully loaded from .env
			applyEnvOverrides(cfg)
			if cfg.Token != "" {
				return cfg, nil
			}
		}
	}

	// Try loading from current directory .env
	if dir == "" {
		cwd, err := os.Getwd()
		if err == nil {
			envPath := filepath.Join(cwd, envFileName)
			if err := loadEnvFile(envPath, cfg); err == nil {
				applyEnvOverrides(cfg)
				if cfg.Token != "" {
					return cfg, nil
				}
			}
		}
	}

	// Try loading from ~/.core/agentic.yaml
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return nil, errors.E("agentic.LoadConfig", "failed to get home directory", err)
	}

	configPath := filepath.Join(homeDir, ".core", configFileName)
	if err := loadYAMLConfig(configPath, cfg); err != nil && !os.IsNotExist(err) {
		return nil, errors.E("agentic.LoadConfig", "failed to load config", err)
	}

	// Apply environment variable overrides
	applyEnvOverrides(cfg)

	// Validate configuration
	if cfg.Token == "" {
		return nil, errors.E("agentic.LoadConfig", "no authentication token configured", nil)
	}

	return cfg, nil
}

// loadEnvFile reads a .env file and extracts agentic configuration.
func loadEnvFile(path string, cfg *Config) error {
	content, err := io.Local.Read(path)
	if err != nil {
		return err
	}

	for _, line := range strings.Split(content, "\n") {
		line = strings.TrimSpace(line)

		// Skip empty lines and comments
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		// Parse KEY=value
		parts := strings.SplitN(line, "=", 2)
		if len(parts) != 2 {
			continue
		}

		key := strings.TrimSpace(parts[0])
		value := strings.TrimSpace(parts[1])

		// Remove quotes if present
		value = strings.Trim(value, `"'`)

		switch key {
		case "AGENTIC_BASE_URL":
			cfg.BaseURL = value
		case "AGENTIC_TOKEN":
			cfg.Token = value
		case "AGENTIC_PROJECT":
			cfg.DefaultProject = value
		case "AGENTIC_AGENT_ID":
			cfg.AgentID = value
		}
	}

	return nil
}

// loadYAMLConfig reads configuration from a YAML file.
func loadYAMLConfig(path string, cfg *Config) error {
	content, err := io.Local.Read(path)
	if err != nil {
		return err
	}

	return yaml.Unmarshal([]byte(content), cfg)
}

// applyEnvOverrides applies environment variable overrides to the config.
func applyEnvOverrides(cfg *Config) {
	if v := os.Getenv("AGENTIC_BASE_URL"); v != "" {
		cfg.BaseURL = v
	}
	if v := os.Getenv("AGENTIC_TOKEN"); v != "" {
		cfg.Token = v
	}
	if v := os.Getenv("AGENTIC_PROJECT"); v != "" {
		cfg.DefaultProject = v
	}
	if v := os.Getenv("AGENTIC_AGENT_ID"); v != "" {
		cfg.AgentID = v
	}
}

// SaveConfig saves the configuration to ~/.core/agentic.yaml.
func SaveConfig(cfg *Config) error {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return errors.E("agentic.SaveConfig", "failed to get home directory", err)
	}

	configDir := filepath.Join(homeDir, ".core")
	if err := io.Local.EnsureDir(configDir); err != nil {
		return errors.E("agentic.SaveConfig", "failed to create config directory", err)
	}

	configPath := filepath.Join(configDir, configFileName)

	data, err := yaml.Marshal(cfg)
	if err != nil {
		return errors.E("agentic.SaveConfig", "failed to marshal config", err)
	}

	if err := io.Local.Write(configPath, string(data)); err != nil {
		return errors.E("agentic.SaveConfig", "failed to write config file", err)
	}

	return nil
}

// ConfigPath returns the path to the config file in the user's home directory.
func ConfigPath() (string, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", errors.E("agentic.ConfigPath", "failed to get home directory", err)
	}
	return filepath.Join(homeDir, ".core", configFileName), nil
}
