<?php

declare(strict_types=1);

namespace Drupal\ai\Plugin\AiPlatform;

use Drupal\ai\Attribute\AiPlatform;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Symfony\AI\Platform\Bridge\Generic\CompletionsModel;
use Symfony\AI\Platform\Bridge\Generic\EmbeddingsModel;
use Symfony\AI\Platform\Bridge\Generic\FallbackModelCatalog;
use Symfony\AI\Platform\Bridge\Generic\ModelCatalog;
use Symfony\AI\Platform\Bridge\Generic\PlatformFactory;
use Symfony\AI\Platform\Capability;
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
use Symfony\AI\Platform\PlatformInterface;

/**
 * Plugin implementation of the "generic" AI provider.
 */
#[AiPlatform(
  id: 'generic',
  label: new TranslatableMarkup('Generic'),
  description: new TranslatableMarkup("Platform that rely on OpenAI's original GPT API, for example, LiteLLM vor OpenRouter."),
)]
final class Generic extends AiPlatformUsingApiKeyAuthenticationPluginBase {

  private const string DEFAULT_COMPLETIONS_PATH = '/v1/chat/completions';

  private const string DEFAULT_EMBEDDINGS_PATH = '/v1/embeddings';

  /**
   * {@inheritdoc}
   */
  protected function initializePlatform(): PlatformInterface {
    $config = $this->getConfiguration();
    return PlatformFactory::create(
      baseUrl: $config['base_url'] ?? '',
      apiKey: $this->getApiKey() ?? '',
      httpClient: $this->httpClient,
      modelCatalog: $this->getModelCatalog(),
      eventDispatcher: $this->eventDispatcher,
      supportsCompletions: $config['supports_completions'],
      supportsEmbeddings: $config['supports_embeddings'],
      completionsPath: $config['completions_path'],
      embeddingsPath: $config['embeddings_path'],
    );
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration(): array {
    return parent::defaultConfiguration() + [
      'base_url' => '',
      'supports_completions' => TRUE,
      'supports_embeddings' => TRUE,
      'completions_path' => self::DEFAULT_COMPLETIONS_PATH,
      'embeddings_path' => self::DEFAULT_EMBEDDINGS_PATH,
      'models' => '',
    ];
  }

  /**
   * Gets the model catalog for the generic provider.
   *
   * Builds a catalog from the configured model names. Uses FallbackModelCatalog
   * as the base so any model name works at runtime, even if not listed.
   *
   * @return \Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface
   *   The model catalog.
   */
  public function getModelCatalog(): ModelCatalogInterface {
    $config = $this->getConfiguration();
    $model_names = array_filter(array_map('trim', explode("\n", $config['models'] ?? '')));
    if (empty($model_names)) {
      return new FallbackModelCatalog();
    }

    $models = [];
    foreach ($model_names as $name) {
      $is_embedding = str_contains(strtolower($name), 'embed');
      $models[$name] = [
        'class' => $is_embedding ? EmbeddingsModel::class : CompletionsModel::class,
        'capabilities' => $is_embedding
          ? [Capability::INPUT_TEXT, Capability::EMBEDDINGS]
          : [Capability::INPUT_MESSAGES, Capability::INPUT_TEXT, Capability::OUTPUT_TEXT, Capability::OUTPUT_STREAMING],
      ];
    }

    return new ModelCatalog($models);
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
    $form = parent::buildConfigurationForm($form, $form_state);
    $config = $this->getConfiguration();

    $form['base_url'] = [
      '#type' => 'url',
      '#title' => $this->t('Base URL'),
      '#description' => $this->t('The API base URL (e.g., https://api.openrouter.ai/api/v1).'),
      '#default_value' => $config['base_url'],
      '#required' => TRUE,
    ];

    $form['supports_completions'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Supports completions'),
      '#default_value' => $config['supports_completions'],
    ];

    $form['completions_path'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Completions path'),
      '#description' => $this->t('The endpoint path for completions. Default: %default', ['%default' => self::DEFAULT_COMPLETIONS_PATH]),
      '#default_value' => $config['completions_path'],
      '#states' => [
        'visible' => [
          ':input[name="configuration[supports_completions]"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['supports_embeddings'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Supports embeddings'),
      '#default_value' => $config['supports_embeddings'],
    ];

    $form['embeddings_path'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Embeddings path'),
      '#description' => $this->t('The endpoint path for embeddings. Default: %default', ['%default' => self::DEFAULT_EMBEDDINGS_PATH]),
      '#default_value' => $config['embeddings_path'],
      '#states' => [
        'visible' => [
          ':input[name="configuration[supports_embeddings]"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['models'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Models'),
      '#description' => $this->t('Enter one model name per line (e.g., gpt-4o, gpt-4o-mini). Models containing "embed" are treated as embedding models, all others as completions models.'),
      '#default_value' => $config['models'],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state): void {
    $values = $form_state->getValue($form['#parents']);

    if ((bool) $values['supports_completions'] && empty($values['completions_path'])) {
      $form_state->setError($form['completions_path'], $this->t('Completions path is required when completions are supported.'));
    }

    if ((bool) $values['supports_embeddings'] && empty($values['embeddings_path'])) {
      $form_state->setError($form['embeddings_path'], $this->t('Embeddings path is required when embeddings are supported.'));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void {
    $values = $form_state->getValue($form['#parents']);

    // Clean up paths if features are disabled to keep configuration clean.
    if (!(bool) $values['supports_completions']) {
      $this->configuration['completions_path'] = self::DEFAULT_COMPLETIONS_PATH;
    }
    if (!(bool) $values['supports_embeddings']) {
      $this->configuration['embeddings_path'] = self::DEFAULT_EMBEDDINGS_PATH;
    }
  }

}
