package providers

import (
	"chat-switchboard/models"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
)

// VeniceProvider handles the Venice.ai API.
// Venice is OpenAI-compatible with extensions: venice_parameters for
// web search, thinking controls, and web scraping.
//
// Ported from ai-editor js/providers/venice.js
type VeniceProvider struct{}

func (p *VeniceProvider) ID() string { return "venice" }

// ── Chat Completion ─────────────────────────
// Delegates to OpenAI provider after injecting venice_parameters.

func (p *VeniceProvider) ChatCompletion(ctx context.Context, cfg ProviderConfig, req CompletionRequest) (*CompletionResponse, error) {
	oai := &OpenAIProvider{}
	return oai.ChatCompletion(ctx, cfg, req)
}

func (p *VeniceProvider) StreamCompletion(ctx context.Context, cfg ProviderConfig, req CompletionRequest) (<-chan StreamEvent, error) {
	oai := &OpenAIProvider{}
	return oai.StreamCompletion(ctx, cfg, req)
}

func (p *VeniceProvider) Embed(ctx context.Context, cfg ProviderConfig, req EmbeddingRequest) (*EmbeddingResponse, error) {
	oai := &OpenAIProvider{}
	return oai.Embed(ctx, cfg, req)
}

// ── List Models ─────────────────────────────
// Venice /v1/models returns model_spec with capabilities, pricing,
// context tokens, and traits. We parse all of it.

func (p *VeniceProvider) ListModels(ctx context.Context, cfg ProviderConfig) ([]Model, error) {
	endpoint := strings.TrimSuffix(cfg.Endpoint, "/") + "/models"

	httpReq, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)
	if err != nil {
		return nil, err
	}
	if cfg.APIKey != "" {
		httpReq.Header.Set("Authorization", "Bearer "+cfg.APIKey)
	}

	resp, err := cfg.Client().Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("venice list models: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		b, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("venice list models: HTTP %d: %s", resp.StatusCode, string(b))
	}

	var result veniceModelsResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("venice decode models: %w", err)
	}

	out := make([]Model, 0, len(result.Data))
	for _, m := range result.Data {
		spec := m.ModelSpec
		vcaps := spec.Capabilities

		caps := models.ModelCapabilities{
			Streaming:     true,
			ToolCalling:   vcaps.SupportsFunctionCalling,
			Vision:        vcaps.SupportsVision,
			Reasoning:     vcaps.SupportsReasoning,
			WebSearch:     vcaps.SupportsWebSearch,
			CodeOptimized: vcaps.OptimizedForCode,
			MaxContext:     spec.AvailableContextTokens,
		}

		// Venice doesn't report max output tokens directly.
		// ResolveMaxOutput will derive from context window at resolution time.

		var pricing *models.ModelPricing
		if spec.Pricing.Input.USD > 0 {
			pricing = &models.ModelPricing{
				InputPerM:  spec.Pricing.Input.USD,
				OutputPerM: spec.Pricing.Output.USD,
			}
		}

		name := spec.Name
		if name == "" {
			name = m.ID
		}

		// Normalize Venice type → our model type
		// Venice returns: "text", "embedding", "image", "code"
		// We normalize to: "chat", "embedding", "image"
		modelType := "chat"
		switch m.Type {
		case "embedding":
			modelType = "embedding"
		case "image":
			modelType = "image"
		default:
			modelType = "chat" // "text", "code", etc. are all chat-capable
		}

		out = append(out, Model{
			ID:           m.ID,
			Name:         name,
			Type:         modelType,
			OwnedBy:      "venice",
			Capabilities: caps,
			Pricing:      pricing,
		})
	}
	return out, nil
}

// ── Venice Wire Types ───────────────────────

type veniceModelsResponse struct {
	Data []veniceModel `json:"data"`
}

type veniceModel struct {
	ID        string          `json:"id"`
	Type      string          `json:"type"`
	OwnedBy   string          `json:"owned_by"`
	ModelSpec veniceModelSpec `json:"model_spec"`
}

type veniceModelSpec struct {
	Name                   string               `json:"name"`
	Description            string               `json:"description"`
	AvailableContextTokens int                  `json:"availableContextTokens"`
	Capabilities           veniceCapabilities   `json:"capabilities"`
	Pricing                venicePricing        `json:"pricing"`
	Traits                 []string             `json:"traits"`
	Offline                bool                 `json:"offline"`
}

type veniceCapabilities struct {
	SupportsFunctionCalling bool `json:"supportsFunctionCalling"`
	SupportsVision          bool `json:"supportsVision"`
	SupportsReasoning       bool `json:"supportsReasoning"`
	SupportsWebSearch       bool `json:"supportsWebSearch"`
	SupportsResponseSchema  bool `json:"supportsResponseSchema"`
	SupportsAudioInput      bool `json:"supportsAudioInput"`
	SupportsLogProbs        bool `json:"supportsLogProbs"`
	OptimizedForCode        bool `json:"optimizedForCode"`
}

type venicePricing struct {
	Input  venicePriceUnit `json:"input"`
	Output venicePriceUnit `json:"output"`
}

type venicePriceUnit struct {
	USD float64 `json:"usd"`
}
