// Package config reads every environment variable the SSR frontend consumes.
//
// The names, defaults and required/optional split mirror the Python service
// exactly (app.py, api_client.py, content.py, paths.py, and the Dockerfile /
// infra/docker-compose.yml PORT wiring). Do not invent new variable names —
// the deploy path (compose + /etc/thermograph.env) sets these and only these.
package config

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

// Config is the fully-resolved runtime configuration.
type Config struct {
	// APIBaseInternal is THERMOGRAPH_API_BASE_INTERNAL — the backend's URL on
	// the compose-internal network (e.g. http://backend:8137). REQUIRED: the
	// Python client raised RuntimeError at import when unset ("a missing
	// backend URL should break the boot, not silently 500 on the first
	// request") — Load returns an error and main exits, same philosophy.
	APIBaseInternal string

	// APIVersion is THERMOGRAPH_API_VERSION (default "v2") — the single pin
	// point for the backend content-API version this service speaks. Bump only
	// in lockstep with a verified backend /api/version check (see
	// frontend CLAUDE.md, "API-version pinning contract").
	APIVersion string

	// Base is THERMOGRAPH_BASE normalized the way content.py normalized it:
	// strip "/" from both ends, then "/"+rest, or "" when the variable is set
	// to "/" (the deployed clean-root topology — the Dockerfile sets "/").
	// Default when unset: "/thermograph" (LAN dev under a sub-path).
	Base string

	// AssetBase is THERMOGRAPH_API_BASE_PUBLIC with any trailing "/" removed,
	// falling back to Base when empty — the browser-facing base for static
	// asset / SPA-shell URLs in templates. Empty var = today's same-origin
	// default, where those references stay relative (ASSET_BASE == BASE).
	AssetBase string

	// SSRCacheTTL is THERMOGRAPH_SSR_CACHE_TTL in seconds (default 600) — the
	// content-API response-cache TTL in the backend client. The Python parsed
	// it with float(env or 600): an empty string means the default, a present
	// but unparsable value crashed the boot — Load mirrors both.
	SSRCacheTTL time.Duration

	// GoogleVerify / BingVerify are THERMOGRAPH_GOOGLE_VERIFY /
	// THERMOGRAPH_BING_VERIFY, whitespace-trimmed; empty = no verification
	// <meta> tag emitted.
	GoogleVerify string
	BingVerify   string

	// Port is PORT (default "8080"). The Python process itself never read it —
	// the Dockerfile's `uvicorn --port ${PORT}` did — but it is the one knob
	// infra uses to move the listen port, so the Go binary reads the same name.
	Port string

	// StaticDir / ContentDir are where static assets and the structured SSR
	// copy (glossary.yaml / pages.yaml) live. The Python resolved these from
	// its own source location (paths.py); a compiled binary has no source
	// directory, so these default to "static" and "content" relative to the
	// working directory — run from frontend/ locally, /app in the image (the
	// Dockerfile must COPY static/ and content/ there and keep WORKDIR /app).
	StaticDir  string
	ContentDir string
}

// Load resolves the configuration from the process environment.
func Load() (Config, error) {
	return load(os.LookupEnv)
}

// load is Load with an injectable environment, for tests.
func load(getenv func(string) (string, bool)) (Config, error) {
	get := func(name, dflt string) string {
		if v, ok := getenv(name); ok {
			return v
		}
		return dflt
	}

	var cfg Config

	cfg.APIBaseInternal, _ = getenv("THERMOGRAPH_API_BASE_INTERNAL")
	if cfg.APIBaseInternal == "" {
		return cfg, fmt.Errorf("THERMOGRAPH_API_BASE_INTERNAL must be set (e.g. http://backend:8137)")
	}

	cfg.APIVersion = get("THERMOGRAPH_API_VERSION", "v2")

	// content.py / api_client.py: os.environ.get("THERMOGRAPH_BASE",
	// "/thermograph").strip("/"), then "/"+base if base else "".
	base := strings.Trim(get("THERMOGRAPH_BASE", "/thermograph"), "/")
	if base != "" {
		cfg.Base = "/" + base
	}

	// content.py: os.environ.get("THERMOGRAPH_API_BASE_PUBLIC", "").rstrip("/") or BASE.
	cfg.AssetBase = strings.TrimRight(get("THERMOGRAPH_API_BASE_PUBLIC", ""), "/")
	if cfg.AssetBase == "" {
		cfg.AssetBase = cfg.Base
	}

	// api_client.py: float(os.environ.get("THERMOGRAPH_SSR_CACHE_TTL", "600") or 600).
	ttlRaw := get("THERMOGRAPH_SSR_CACHE_TTL", "600")
	if ttlRaw == "" {
		ttlRaw = "600"
	}
	ttlSecs, err := strconv.ParseFloat(ttlRaw, 64)
	if err != nil {
		// The Python raised ValueError at import for a garbage value — fail
		// loud here too rather than silently running with a wrong TTL.
		return cfg, fmt.Errorf("THERMOGRAPH_SSR_CACHE_TTL: %w", err)
	}
	cfg.SSRCacheTTL = time.Duration(ttlSecs * float64(time.Second))

	cfg.GoogleVerify = strings.TrimSpace(get("THERMOGRAPH_GOOGLE_VERIFY", ""))
	cfg.BingVerify = strings.TrimSpace(get("THERMOGRAPH_BING_VERIFY", ""))

	cfg.Port = get("PORT", "8080")
	cfg.StaticDir = "static"
	cfg.ContentDir = "content"
	return cfg, nil
}
