<?php

declare(strict_types=1);

namespace KimaAI\Ai\Providers\Ollama;

use KimaAI\Ai\Providers\Http\HttpClientInterface;
use KimaAI\Ai\Providers\OpenAI\OpenAiClient;
use KimaAI\Ai\Providers\Support\Capability;
use KimaAI\Ai\Providers\Support\ProviderMetadata;


/**
 * Ollama provider using the OpenAI-compatible API.
 *
 * Best practice:
 * - Reuse OpenAI-compatible endpoints where possible.
 * - Override only provider-specific behavior.
 * - Keep Responses API non-stateful, because Ollama does not support
 *   previous_response_id / conversation continuation on /v1/responses.
 */
class OllamaClient extends OpenAiClient {
  public function __construct(
    string $api_key = 'ollama',
    ?string $organization = null,
    string $base_url = 'http://localhost:11434/v1',
    ?HttpClientInterface $http_client = null
  ) {
    parent::__construct($api_key, $organization, $base_url, $http_client);

    // Ollama image support exists but is experimental, so do not advertise
    // broad image-model support unless you manage that elsewhere.
    $this->ai_image_models = [];
  }

  public function metadata(): ProviderMetadata {
    return new ProviderMetadata('ollama', 'Ollama', $this->base_url, [
      Capability::CHAT,
      Capability::STREAMING_CHAT,
      Capability::RESPONSES,
      Capability::EMBEDDING,
      Capability::MODELS,
      Capability::OPENAI_COMPATIBLE,
    ]);
  }

  /**
   * Ollama local API does not require authentication, but cloud access can use
   * bearer auth. To stay compatible with both:
   * - send Content-Type always
   * - send Accept: text/event-stream for streaming
   * - send Authorization only when apiKey is non-empty
   * - do not send OpenAI-Organization
   */
  protected function buildHeaders(bool $stream): array {
    $headers = [
      'Content-Type: application/json',
    ];

    if ($this->api_key !== '') {
      $headers[] = 'Authorization: Bearer ' . $this->api_key;
    }

    if ($stream) {
      $headers[] = 'Accept: text/event-stream';
    }

    return $headers;
  }

  /**
   * Ollama supports the OpenAI Responses API, but only the non-stateful flavor.
   */
  public function responses(): \KimaAI\Ai\Providers\OpenAI\Endpoint\Responses {
    return new \KimaAI\Ai\Providers\OpenAI\Endpoint\Responses($this);
  }

  /**
   * Ollama-specific chat handling:
   * - Reuse /v1/responses when payload uses `input`
   * - Strip unsupported stateful params proactively
   * - Otherwise use /v1/chat/completions
   */
  public function chat(array $payload): array {
    $allowed_args = array_intersect_key($payload, $this->allowed_args);

    // Ollama /v1/responses is non-stateful only.
    unset($allowed_args['previous_response_id']);

    if (isset($payload['input'])) {
      return $this->responses()->create($allowed_args, false);
    }

    return $this->runChat()->create($allowed_args);
  }

  /**
   * Streaming chat handling for Ollama.
   */
  public function chatStream(array $payload, callable $on_chunk): array {
    $allowed_args = array_intersect_key($payload, $this->allowed_args);

    unset($allowed_args['previous_response_id']);
    $allowed_args['stream'] = true;

    if (isset($payload['input'])) {
      return $this->responses()->create($allowed_args, true, $on_chunk);
    }

    return $this->request('POST', '/chat/completions', $allowed_args, true, [], $on_chunk);
  }
}
