package config

import (
	"encoding/json"
	"errors"
	"os"
	"path/filepath"
)

// LLMFileName is the filename under the Astra config directory.
const LLMFileName = "llm.json"

type llmFileRecord struct {
	APIKey      string `json:"api_key,omitempty"`
	BaseURL     string `json:"base_url,omitempty"`
	Model       string `json:"model,omitempty"`
	FastModel   string `json:"fast_model,omitempty"`
	AstraAPIKey string `json:"astra_api_key,omitempty"`
}

// LLMConfigDir returns ~/.astra (created by callers when saving).
func LLMConfigDir() (string, error) {
	home, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(home, ".astra"), nil
}

// LLMFilePath returns the path to the saved LLM credentials file (~/.astra/llm.json).
func LLMFilePath() (string, error) {
	dir, err := LLMConfigDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(dir, LLMFileName), nil
}

// LoadLLMFile reads ~/.astra/llm.json if it exists. Missing file is not an error.
func LoadLLMFile() (LLMEnv, error) {
	path, err := LLMFilePath()
	if err != nil {
		return LLMEnv{}, err
	}
	data, err := os.ReadFile(path)
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return LLMEnv{}, nil
		}
		return LLMEnv{}, err
	}
	var rec llmFileRecord
	if err := json.Unmarshal(data, &rec); err != nil {
		return LLMEnv{}, err
	}
	return LLMEnv{
		APIKey:      rec.APIKey,
		BaseURL:     rec.BaseURL,
		Model:       rec.Model,
		FastModel:   rec.FastModel,
		AstraAPIKey: rec.AstraAPIKey,
	}, nil
}

// SaveLLMFile writes LLM settings to ~/.astra/llm.json with 0600 permissions.
func SaveLLMFile(cfg LLMEnv) error {
	dir, err := LLMConfigDir()
	if err != nil {
		return err
	}
	if err := os.MkdirAll(dir, 0700); err != nil {
		return err
	}
	path := filepath.Join(dir, LLMFileName)
	rec := llmFileRecord{
		APIKey:      cfg.APIKey,
		BaseURL:     cfg.BaseURL,
		Model:       cfg.Model,
		FastModel:   cfg.FastModel,
		AstraAPIKey: cfg.AstraAPIKey,
	}
	data, err := json.MarshalIndent(rec, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(path, data, 0600)
}

// LoadLLMForCLI loads LLM config for the CLI.
//
// Priority: if ~/.astra/llm.json has a complete config (api_key + base_url + model),
// use it as-is — this prevents stale env vars from partially overriding the file
// and creating key/URL mismatches (e.g. OpenRouter key sent to Gemini endpoint).
//
// Env vars (LLM_API_KEY, LLM_BASE_URL, LLM_MODEL) are only used as fallbacks
// when the file config is missing or incomplete.
//
// If an Astra platform key is found (file or env), it is injected into ASTRA_API_KEY
// so that downstream code (hasAuthToken, resolveAuthToken) picks it up automatically.
func LoadLLMForCLI() LLMEnv {
	file, _ := LoadLLMFile()

	fileComplete := file.APIKey != "" && file.BaseURL != "" && file.Model != ""

	var apiKey, baseURL, model, fastModel string

	if fileComplete {
		apiKey = file.APIKey
		baseURL = file.BaseURL
		model = file.Model
		fastModel = file.FastModel
	} else {
		apiKey = firstNonEmpty(os.Getenv("LLM_API_KEY"), os.Getenv("OPENAI_API_KEY"), file.APIKey)
		baseURL = firstNonEmpty(os.Getenv("LLM_BASE_URL"), file.BaseURL)
		model = firstNonEmpty(os.Getenv("LLM_MODEL"), file.Model, "anthropic/claude-sonnet-4")
		fastModel = firstNonEmpty(os.Getenv("LLM_FAST_MODEL"), file.FastModel)
	}

	if fastModel == "" {
		fastModel = DeriveFastModel(model)
	}

	astraKey := firstNonEmpty(
		os.Getenv("ASTRA_API_KEY"),
		os.Getenv("ASTRA_ACCESS_TOKEN"),
		file.AstraAPIKey,
	)
	if astraKey != "" && os.Getenv("ASTRA_API_KEY") == "" {
		os.Setenv("ASTRA_API_KEY", astraKey)
	}

	return LLMEnv{
		APIKey:      apiKey,
		BaseURL:     baseURL,
		Model:       model,
		FastModel:   fastModel,
		AstraAPIKey: astraKey,
	}
}
