<?php

namespace KimaAI\Ai;

use KimaAI\Admin\Settings;
use RuntimeException;

class EnvResolver {

  /**
   * Create the environment resolver.
   */
  public function __construct(
    public Settings $settings,
  ) {
  }

  /**
   * Resolve provider, model and API-key for a given AI environment.
   *
   * `$env_id` can be…
   *   • one of the logical aliases:  "default", "chat", "image", "embed"
   *   • a full slug:                "openai-6872453c84041"
   *   • the bare environment ID:    "6872453c84041"
   *   • a provider name:            "openai", "ollama", "openrouter"
   *
   * @param string $env_id Alias / slug / ID / provider. Pass "default" by default.
   * @param string|null $model Optional model override.
   * @return array
   *
   * @throws RuntimeException If anything is missing, ambiguous, or cannot be resolved.
   */
  public function resolve(string $env_id = 'default', ?string $model = null): array {
    $ai_service_settings = $this->settings->getOption(null, 'aiServices');
    $envs = $ai_service_settings['aiEnvs'] ?? [];
    $presets = $ai_service_settings['aiPresets'] ?? [];

    $requested_env = trim($env_id);
    $resolved_model = null;
    $resolved_alias = null;

    // 1. Decide which preset keys belong to the requested alias.
    $aliases = [
      'default' => [
        'envKey' => 'defaultEnv',
        'modelKey' => 'defaultModel',
      ],
      'chat' => [
        'envKey' => 'chatEnv',
        'modelKey' => 'chatModel',
      ],
      'image' => [
        'envKey' => 'imageEnv',
        'modelKey' => 'imageModel',
      ],
      'embed' => [
        'envKey' => 'embedEnv',
        'modelKey' => 'embedModel',
      ],
    ];

    if (isset($aliases[$requested_env])) {
      $resolved_alias = $requested_env;
      $alias = $aliases[$requested_env];
      $preset_env = $presets[$alias['envKey']] ?? null;
      $resolved_model = $presets[$alias['modelKey']] ?? null;

      if (!$preset_env || $preset_env === 'none') {
        throw new RuntimeException(sprintf(
          'No "%s" AI environment set in Settings → AI Presets.',
          esc_html($requested_env)
        ));
      }

      // Keep the preset value as-is (usually a slug like "openai-69ad40f315ba8")
      // and let the resolver below handle it.
      $requested_env = trim((string) $preset_env);
    }

    // 2. Find the environment row (provider + key).
    // We support matching by:
    // - exact bare ID
    // - exact slug: "{provider}-{id}"
    // - exact provider name
    $matches = [];

    foreach ($envs as $env) {
      $env_id_in_loop = trim((string) ($env['id'] ?? ''));
      $provider_in_loop = trim((string) ($env['provider'] ?? ''));

      if ($env_id_in_loop === '' || $provider_in_loop === '') {
        continue;
      }

      $slug_in_loop = $provider_in_loop . '-' . $env_id_in_loop;

      if (
        $requested_env === $env_id_in_loop ||
        $requested_env === $slug_in_loop ||
        $requested_env === $provider_in_loop
      ) {
        $matches[] = $env;
      }
    }

    if (!$matches) {
      throw new RuntimeException(sprintf(
        'AI environment "%s" not found. Use an alias, provider, slug, or env ID. Create it in Settings → AI Envs.',
        esc_html($requested_env)
      ));
    }

    if (count($matches) > 1) {
      $matching_labels = array_map(
        static fn(array $env): string => sprintf(
          '%s-%s',
          (string) ($env['provider'] ?? 'unknown'),
          (string) ($env['id'] ?? 'unknown')
        ),
        $matches
      );

      throw new RuntimeException(sprintf(
        'AI environment "%s" is ambiguous. Matching environments: %s. Use the full slug or bare env ID instead.',
        esc_html($requested_env),
        esc_html(implode(', ', $matching_labels))
      ));
    }

    $found_env = $matches[0];

    $provider = trim((string) ($found_env['provider'] ?? ''));
    $api_key = $found_env['apiKey'] ?? null;
    $endpoint = isset($found_env['endpoint']) ? trim((string) $found_env['endpoint']) : '';
    $resolved_env_id = trim((string) ($found_env['id'] ?? ''));
    $resolved_slug = $provider . '-' . $resolved_env_id;

    if (!$provider || (!$api_key && $provider !== 'ollama')) {
      throw new RuntimeException(sprintf(
        'AI environment "%s" is missing a provider or API key in settings.',
        esc_html($requested_env)
      ));
    }

    // 3. Resolve the model (models live in presets, not on env rows).
    if ($resolved_model === null || $resolved_model === '') {
      $map = [
        'defaultEnv' => 'defaultModel',
        'chatEnv' => 'chatModel',
        'imageEnv' => 'imageModel',
        'embedEnv' => 'embedModel',
      ];

      foreach ($map as $env_key => $model_key) {
        if (!isset($presets[$env_key], $presets[$model_key])) {
          continue;
        }

        $preset_env_value = trim((string) $presets[$env_key]);
        if ($preset_env_value === $resolved_slug) {
          $resolved_model = $presets[$model_key];
          break;
        }
      }
    }

    if ($resolved_model === null || $resolved_model === '') {
      $resolved_model = $model;
    }

    if ($resolved_model === null || $resolved_model === '') {
      throw new RuntimeException(sprintf(
        'No model defined for AI environment "%s". Add it in Settings → AI Presets or pass a model override.',
        esc_html($requested_env)
      ));
    }

    $preset_params = [];
    if ($resolved_alias !== null) {
      foreach (['Temperature', 'Reasoning', 'Verbosity'] as $suffix) {
        $key = $resolved_alias . $suffix;
        if (isset($presets[$key]) && $presets[$key] !== '') {
          $preset_params[strtolower($suffix)] = $presets[$key];
        }
      }
    }

    return [
      'provider' => $provider,
      'model' => $resolved_model,
      'apiKey' => $api_key,
      'endpoint' => $endpoint,
      'env_id' => $resolved_env_id,
      'preset_params' => $preset_params,
    ];
  }
}
