// Package providers — custom.go
//
// v0.29.1 CS4: Config-file provider types. Registers OpenAI-compatible
// provider types from a JSON file at startup. No code deploy needed to
// add Ollama, LiteLLM, vLLM, or any other OpenAI-compatible endpoint.
//
// File format (array of objects):
//
//	[
//	  {
//	    "id": "ollama",
//	    "name": "Ollama",
//	    "description": "Local Ollama instance",
//	    "default_endpoint": "http://localhost:11434/v1",
//	    "api": "openai"
//	  },
//	  {
//	    "id": "litellm",
//	    "name": "LiteLLM Proxy",
//	    "description": "LiteLLM unified proxy",
//	    "default_endpoint": "http://litellm:4000/v1",
//	    "api": "openai"
//	  }
//	]
//
// Fields:
//   - id:               Unique provider type ID (used in provider_configs.provider column)
//   - name:             Human-readable label for admin UI
//   - description:      Help text shown in provider creation form
//   - default_endpoint: Pre-filled endpoint URL for new configs
//   - api:              Wire protocol — "openai" (required, only supported value for now)
//
// The api field determines which Provider implementation handles
// requests. Currently only "openai" is supported (covers Ollama,
// LiteLLM, vLLM, LocalAI, and any other OpenAI-compatible API).
// Future: "anthropic" for Anthropic-compatible proxies.
//
// Built-in provider IDs (openai, anthropic, venice, openrouter) cannot
// be overridden by config-file entries — they are silently skipped.
package providers

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// CustomProviderType represents one entry in the provider types JSON file.
type CustomProviderType struct {
	ID              string `json:"id"`
	Name            string `json:"name"`
	Description     string `json:"description"`
	DefaultEndpoint string `json:"default_endpoint"`
	API             string `json:"api"` // "openai" (required)
}

// builtinIDs is the set of provider IDs registered by Init().
// Config-file entries with these IDs are silently skipped.
var builtinIDs = map[string]bool{
	"openai":     true,
	"anthropic":  true,
	"venice":     true,
	"openrouter": true,
}

// LoadCustomTypes reads a JSON file of provider type definitions and
// registers each as a new provider type. Only OpenAI-compatible APIs
// are currently supported (api="openai").
//
// Returns the number of providers registered. Errors are non-fatal —
// individual invalid entries are logged and skipped.
//
// Call after Init() so that built-in types are already registered
// and can be detected for skip logic.
func LoadCustomTypes(path string) (int, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return 0, fmt.Errorf("reading provider types file: %w", err)
	}

	var entries []CustomProviderType
	if err := json.Unmarshal(data, &entries); err != nil {
		return 0, fmt.Errorf("parsing provider types file: %w", err)
	}

	registered := 0
	for _, entry := range entries {
		// Validate required fields
		if entry.ID == "" {
			log.Printf("⚠️ custom provider: skipping entry with empty id")
			continue
		}
		if entry.Name == "" {
			log.Printf("⚠️ custom provider %q: skipping — name is required", entry.ID)
			continue
		}
		if entry.API == "" {
			log.Printf("⚠️ custom provider %q: skipping — api is required", entry.ID)
			continue
		}

		// Skip built-in provider IDs
		if builtinIDs[entry.ID] {
			log.Printf("⚠️ custom provider %q: skipping — conflicts with built-in provider", entry.ID)
			continue
		}

		// Resolve API implementation
		var impl Provider
		switch entry.API {
		case "openai":
			impl = &OpenAIProvider{}
		default:
			log.Printf("⚠️ custom provider %q: unsupported api %q (only \"openai\" supported)", entry.ID, entry.API)
			continue
		}

		RegisterType(ProviderTypeMeta{
			ID:              entry.ID,
			Name:            entry.Name,
			Description:     entry.Description,
			DefaultEndpoint: entry.DefaultEndpoint,
			ProfileSchema:   GetProfileSchema(entry.API), // inherit schema from API type
		}, impl)

		registered++
		log.Printf("  📦 Custom provider type: %s (%s) → %s", entry.ID, entry.Name, entry.DefaultEndpoint)
	}

	return registered, nil
}
