<?php

declare(strict_types=1);

namespace Drupal\flowdrop_ai_context\Controller\Api;

use Drupal\ai_context\AiContextScopeManager;
use Drupal\ai_context\Service\AiContextRequestFactory;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Url;
use Drupal\flowdrop\Controller\Api\ApiResponseTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * API controller for AI Context Item discovery and detail.
 *
 * @internal
 */
final class AiContextApiController extends ControllerBase {

  use ApiResponseTrait;

  /**
   * Constructs an AiContextApiController.
   */
  public function __construct(
    private readonly AiContextScopeManager $scopeManager,
    private readonly AiContextRequestFactory $requestFactory,
  ) {}

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('plugin.manager.ai_context_scope'),
      $container->get('ai_context.request_factory'),
    );
  }

  /**
   * Autocomplete search for AI Context Items by label.
   */
  public function autocomplete(Request $request): JsonResponse {
    try {
      $q = trim((string) $request->query->get('q', ''));
      $storage = $this->entityTypeManager()->getStorage('ai_context_item');

      $query = $storage->getQuery()
        ->accessCheck(TRUE)
        ->condition('status', 1)
        ->sort('label', 'ASC')
        ->range(0, 50);

      if ($q !== '') {
        $query->condition('label', '%' . $q . '%', 'LIKE');
      }

      $ids = $query->execute();

      $results = [];
      if (!empty($ids)) {
        $items = $storage->loadMultiple($ids);
        foreach ($items as $item) {
          if (!$item->access('view')) {
            continue;
          }
          $results[] = [
            'value' => (string) $item->id(),
            'label' => (string) $item->label(),
            'type' => (string) $item->bundle(),
          ];
        }
      }

      $addUrl = '';
      try {
        $addUrl = Url::fromRoute('entity.ai_context_item.add_form')->toString();
      }
      catch (\Exception) {
        // Route may not exist in all configurations.
      }

      return new JsonResponse([
        'results' => $results,
        'add_url' => $addUrl,
      ]);
    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_ai_context')->error(
        'Error searching AI Context Items: @error',
        ['@error' => $e->getMessage()],
      );

      return new JsonResponse(
        ['results' => [], 'add_url' => ''],
        Response::HTTP_INTERNAL_SERVER_ERROR,
      );
    }
  }

  /**
   * Returns detail for a single AI Context Item.
   *
   * @param string $context_id
   *   The AI Context Item entity ID.
   */
  public function getItem(string $context_id): JsonResponse {
    try {
      $id = (int) $context_id;
      if ($id <= 0) {
        return $this->errorResponse('Invalid context item ID', Response::HTTP_BAD_REQUEST);
      }

      $storage = $this->entityTypeManager()->getStorage('ai_context_item');
      $entity = $storage->load($id);

      if ($entity === NULL || !$entity->isPublished() || !$entity->access('view')) {
        return $this->errorResponse(
          "AI Context Item '$context_id' not found",
          Response::HTTP_NOT_FOUND,
        );
      }

      $editUrl = '';
      try {
        $editUrl = Url::fromRoute(
          'entity.ai_context_item.edit_form',
          ['ai_context_item' => $id],
        )->toString();
      }
      catch (\Exception) {
        // Route may not exist in all configurations.
      }

      return $this->successResponse([
        'id' => (string) $entity->id(),
        'label' => (string) $entity->label(),
        'type' => (string) $entity->bundle(),
        'purpose' => $entity->getPurpose(),
        'content_preview' => mb_substr($entity->getContent(), 0, 300),
        'edit_url' => $editUrl,
      ]);
    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_ai_context')->error(
        'Error fetching AI Context Item @id: @error',
        ['@id' => $context_id, '@error' => $e->getMessage()],
      );

      return $this->errorResponse(
        'Failed to fetch context item detail',
        Response::HTTP_INTERNAL_SERVER_ERROR,
      );
    }
  }

  /**
   * Returns subscribable AI Context scopes and their available values.
   *
   * Feeds the scope-subscription field widget on the AI Context node. Only
   * enabled scopes that support agent/consumer subscriptions are returned.
   */
  public function scopes(): JsonResponse {
    try {
      $scopes = [];
      foreach ($this->scopeManager->getScopePlugins() as $plugin) {
        if (!$plugin->isEnabled() || !$plugin->supportsSubscriptions()) {
          continue;
        }

        $values = [];
        foreach ($plugin->getValues() as $valueId => $label) {
          $values[] = [
            'value' => (string) $valueId,
            'label' => (string) $label,
          ];
        }

        $scopes[] = [
          'id' => $plugin->getId(),
          'label' => (string) $plugin->getLabel(),
          'description' => (string) $plugin->getSubscriptionDescription(),
          'allows_multiple' => $plugin->allowsMultiple(),
          'values' => $values,
        ];
      }

      return new JsonResponse(['scopes' => $scopes]);
    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_ai_context')->error(
        'Error listing AI Context scopes: @error',
        ['@error' => $e->getMessage()],
      );

      return new JsonResponse(['scopes' => []], Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Returns the Context Control Center settings URL for an agent.
   *
   * Lets the FlowDrop agent picker deep-link to the per-agent context
   * configuration page, mirroring the link the ai_context module adds to the
   * AI Agent edit form. Returns an empty URL when the route is unavailable
   * (e.g. the installed ai_context version predates per-agent settings).
   *
   * @param string $agent_id
   *   The AI agent plugin/config ID.
   */
  public function agentContextUrl(string $agent_id): JsonResponse {
    $url = '';
    try {
      // The CCC per-agent settings form only supports config-based ai_agent
      // entities; plugin/code-based agents have no entity to configure and
      // would land on an "Agent not found" page. Only return a URL when a
      // matching config entity exists, so the widget hides the link for
      // plugin agents.
      $agent = $this->entityTypeManager()->getStorage('ai_agent')->load($agent_id);
      if ($agent !== NULL) {
        $url = Url::fromRoute(
          'ai_context.context_agent_edit',
          ['ai_agent' => $agent_id],
        )->toString();
      }
    }
    catch (\Exception) {
      // ai_agent storage or route unavailable; degrade gracefully.
    }

    // Whether the agent actually carries CCC context config. Only then do its
    // scopes take over from the node's manual Scope Subscriptions; plugin
    // agents (and unconfigured agents) carry none, so manual scopes stay.
    $hasContextConfig = $agent_id !== ''
      && $this->requestFactory->findAgentConfig($agent_id) !== [];

    return new JsonResponse([
      'url' => $url,
      'has_context_config' => $hasContextConfig,
    ]);
  }

}
