// Package ollama provides an Adapter that calls a local Ollama server.
package ollama

import (
	"context"
	"net/http"
	"strings"
	"time"

	"go.uber.org/zap"

	"iop/packages/go/config"
	runtime "iop/packages/go/execution"
)

const Name = "ollama"

const runtimeMetadataOpenAIToolCalls = "openai_tool_calls"

type Ollama struct {
	instanceName     string
	baseURL          string
	contextSize      int
	capacity         int
	maxQueue         int
	queueTimeoutMS   int
	requestTimeoutMS int
	client           *http.Client
	logger           *zap.Logger
}

// New creates an Ollama adapter. The optional instanceName is the registry
// instance key used to disambiguate multiple Ollama instances on the same node.
func New(cfg config.OllamaConf, logger *zap.Logger, instanceName ...string) *Ollama {
	baseURL := strings.TrimRight(cfg.BaseURL, "/")
	if baseURL == "" {
		baseURL = "http://localhost:11434"
	}
	name := Name
	if len(instanceName) > 0 && instanceName[0] != "" {
		name = instanceName[0]
	}
	return &Ollama{
		instanceName:     name,
		baseURL:          baseURL,
		contextSize:      cfg.ContextSize,
		capacity:         cfg.Capacity,
		maxQueue:         cfg.MaxQueue,
		queueTimeoutMS:   cfg.QueueTimeoutMS,
		requestTimeoutMS: cfg.RequestTimeoutMS,
		client:           &http.Client{},
		logger:           logger,
	}
}

func (o *Ollama) Name() string { return Name }

func (o *Ollama) Capabilities(ctx context.Context) (runtime.Capabilities, error) {
	probeCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
	defer cancel()
	targets, err := o.fetchTargets(probeCtx)
	status := runtime.ProviderStatusAvailable
	if err != nil {
		status = runtime.ProviderStatusUnavailable
	}
	return runtime.Capabilities{
		AdapterName:      Name,
		InstanceKey:      o.instanceName,
		Targets:          targets,
		MaxConcurrency:   effectiveCapacity(o.capacity, 4),
		MaxQueue:         o.maxQueue,
		QueueTimeoutMS:   o.queueTimeoutMS,
		RequestTimeoutMS: o.requestTimeoutMS,
		ProviderStatus:   runtime.NormalizeProviderStatus(status),
	}, nil
}

func effectiveCapacity(capacity, defaultVal int) int {
	if capacity <= 0 {
		return defaultVal
	}
	return capacity
}
