<?php

declare(strict_types=1);

namespace Drupal\flowdrop_chat\Service;

use Drupal\ai\AiProviderPluginManager;
use Drupal\ai\OperationType\Chat\ChatInput;
use Drupal\ai\OperationType\Chat\ChatMessage;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\flowdrop_ai_provider\Service\AiModelService;

/**
 * LLM client for the FlowDrop Chat module.
 */
class ChatLlmClient implements ChatLlmClientInterface {

  /**
   * Constructs a new ChatLlmClient.
   *
   * @param \Drupal\flowdrop_ai_provider\Service\AiModelService $aiModelService
   *   The FlowDrop AI model service for model discovery.
   * @param \Drupal\ai\AiProviderPluginManager $aiProviderManager
   *   The AI provider plugin manager for executing requests.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   */
  public function __construct(
    protected readonly AiModelService $aiModelService,
    protected readonly AiProviderPluginManager $aiProviderManager,
    protected readonly ConfigFactoryInterface $configFactory,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function chat(string $systemPrompt, string $userPrompt, array $tags = []): string {
    [$providerId, $modelId] = $this->resolveProviderAndModel();

    $provider = $this->aiProviderManager->createInstance($providerId);

    $messages = [
      new ChatMessage('user', $userPrompt),
    ];

    $input = new ChatInput($messages);
    $input->setSystemPrompt($systemPrompt);
    $input->setStreamedOutput(FALSE);

    // ProviderProxy uses __call to delegate to the underlying ChatInterface.
    // @phpstan-ignore method.notFound
    $output = $provider->chat($input, $modelId, $tags);
    $normalized = $output->getNormalized();

    return $normalized->getText();
  }

  /**
   * Resolves provider ID and model ID from config or system defaults.
   *
   * @return array{0: string, 1: string}
   *   A tuple of [providerId, modelId].
   */
  protected function resolveProviderAndModel(): array {
    $configured = $this->configFactory
      ->get('flowdrop_chat.settings')
      ->get('llm_provider') ?? '';

    // Parse configured "provider:model" value.
    if (!empty($configured) && str_contains($configured, ':')) {
      [$providerId, $modelId] = explode(':', $configured, 2);
      return [$providerId, $modelId];
    }

    // Fall back to system default.
    $modelId = $this->aiModelService->getDefaultModelForOperationType('chat');

    if (empty($modelId)) {
      $available = $this->aiModelService->getAvailableModels('chat');
      $modelIds = array_keys($available);
      $modelId = !empty($modelIds) ? $modelIds[0] : '';
    }

    if (empty($modelId)) {
      throw new \RuntimeException('No AI models configured for chat operations. Please configure at least one AI provider.');
    }

    $modelConfig = $this->aiModelService->getModel($modelId, 'chat');
    if (!$modelConfig) {
      throw new \RuntimeException('Configured AI model is not available for chat operations.');
    }

    return [$modelConfig['provider'], $modelId];
  }

}
