package chat

import (
	"bufio"
	"log/slog"
	"os"
	"strings"
	"time"
)

// BuilderInput drives provider construction. Each field maps to one
// provider; empty fields mean "skip" (the registry won't have that
// provider — :cloud suffix or openrouter/* prefixes will 404 cleanly).
type BuilderInput struct {
	OllamaURL       string        // local Ollama, no auth (typically http://localhost:11434)
	OllamaCloudKey  string        // OLLAMA_CLOUD_KEY
	OpenRouterKey   string        // OPENROUTER_API_KEY
	OpenCodeKey     string        // OPENCODE_API_KEY
	KimiKey         string        // KIMI_API_KEY
	Timeout         time.Duration // default 180s
}

// BuildRegistry constructs a Registry from the input. Logs which
// providers were registered (for operator confidence at boot).
func BuildRegistry(in BuilderInput) *Registry {
	if in.Timeout == 0 {
		in.Timeout = 180 * time.Second
	}

	var providers []Provider
	registered := []string{}

	// Local Ollama always registered if URL given (no auth needed).
	if in.OllamaURL != "" {
		providers = append(providers, NewOllama(in.OllamaURL, in.Timeout))
		registered = append(registered, "ollama")
	}
	if in.OllamaCloudKey != "" {
		providers = append(providers, NewOllamaCloud(in.OllamaCloudKey, in.Timeout))
		registered = append(registered, "ollama_cloud")
	}
	if in.OpenRouterKey != "" {
		providers = append(providers, NewOpenRouter(in.OpenRouterKey, in.Timeout))
		registered = append(registered, "openrouter")
	}
	if in.OpenCodeKey != "" {
		providers = append(providers, NewOpenCode(in.OpenCodeKey, in.Timeout))
		registered = append(registered, "opencode")
	}
	if in.KimiKey != "" {
		providers = append(providers, NewKimi(in.KimiKey, in.Timeout))
		registered = append(registered, "kimi")
	}

	r := NewRegistry(providers...)
	slog.Info("chat registry built", "providers", registered)
	return r
}

// ResolveKey reads an API key with the priority chain:
//   1. Explicit env var (named by envVar)
//   2. .env file at envFilePath, looking for "<envVar>=<value>" line
//   3. "" if neither set
//
// Mirrors the Rust adapter's resolve_*_key() pattern. Empty key
// means the provider stays unregistered — operators see one fewer
// entry in the boot log instead of a 503 at first request.
//
// Phase 4 scrum fix B-1 (Opus + Kimi convergent): collapsed from
// 3-arg API to 2-arg. Previous version forced callers to pass the
// env var name twice (once for env-lookup, once for file-key-lookup),
// which let operator renames silently miss the file fallback. Now
// both lookups use the same canonical name. Operators who want a
// different file-key-name can use a different env var altogether.
func ResolveKey(envVar, envFilePath string) string {
	if envVar != "" {
		if v := strings.TrimSpace(os.Getenv(envVar)); v != "" {
			return v
		}
	}
	if envFilePath != "" && envVar != "" {
		if v := readEnvFileVar(envFilePath, envVar); v != "" {
			return v
		}
	}
	return ""
}

// readEnvFileVar reads a KEY=value style env file and returns the
// value of `name`. Returns "" on any error or missing key. Stops at
// first match. No quoting/escaping — same simple shape that systemd
// EnvironmentFile= reads.
func readEnvFileVar(path, name string) string {
	f, err := os.Open(path)
	if err != nil {
		return ""
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	prefix := name + "="
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		if strings.HasPrefix(line, prefix) {
			return strings.Trim(strings.TrimPrefix(line, prefix), `"'`)
		}
	}
	return ""
}
