<?php

namespace Drupal\nodehive_public_api\Controller;

use Drupal\Core\Cache\CacheableJsonResponse;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\nodehive_core\MenuHelperInterface;
use Drupal\nodehive_public_api\ApiResponseTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Controller for API index endpoint.
 */
class ApiController extends ControllerBase {

  use ApiResponseTrait;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Constructs an ApiController object.
   *
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(
    LanguageManagerInterface $language_manager,
    RequestStack $request_stack,
    EntityTypeManagerInterface $entity_type_manager,
  ) {
    $this->languageManager = $language_manager;
    $this->requestStack = $request_stack;
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('language_manager'),
      $container->get('request_stack'),
      $container->get('entity_type.manager')
    );
  }

  /**
   * Redirects from /nodehive-api to /nodehive-api/v1.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   The redirect response.
   */
  public function redirectToV1(): RedirectResponse {
    $current_language = $this->languageManager->getCurrentLanguage();
    $language_prefixes = $this->config('language.negotiation')->get('url.prefixes');
    $prefix = !empty($language_prefixes[$current_language->getId()]) ? '/' . $language_prefixes[$current_language->getId()] : '';

    $url = $prefix . '/nodehive-api/v1';
    return new RedirectResponse($url, 301);
  }

  /**
   * Returns the list of available API endpoints.
   *
   * @return \Drupal\Core\Cache\CacheableJsonResponse
   *   The JSON response containing available endpoints.
   */
  public function index(): CacheableJsonResponse {
    try {
      $request = $this->requestStack->getCurrentRequest();
      $base_url = $request->getSchemeAndHttpHost();
      $languages = $this->languageManager->getLanguages();
      $language_codes = array_keys($languages);

      // Get language prefix configuration.
      $language_prefixes = $this->config('language.negotiation')->get('url.prefixes');

      // Load all available menus.
      $menu_storage = $this->entityTypeManager->getStorage('menu');
      $menus = $menu_storage->loadMultiple();

      $available_menus = [];
      foreach ($menus as $menu) {
        $menu_id = $menu->id();

        // Skip system menus.
        if (in_array($menu_id, MenuHelperInterface::API_EXCLUDED_MENUS)) {
          continue;
        }

        $menu_urls = [];

        // Build URLs for each language.
        foreach ($language_codes as $langcode) {
          $prefix = !empty($language_prefixes[$langcode]) ? '/' . $language_prefixes[$langcode] : '';
          $menu_urls[$langcode] = $base_url . $prefix . '/nodehive-api/v1/menu/' . $menu_id;
        }

        $available_menus[] = [
          'id' => $menu_id,
          'label' => $menu->label(),
          'description' => $menu->getDescription(),
          'urls' => $menu_urls,
        ];
      }

      // Load all available spaces.
      $space_storage = $this->entityTypeManager->getStorage('nodehive_space');
      $spaces = $space_storage->loadMultiple();

      $available_spaces = [];
      $available_spaces_with_urls = [];
      foreach ($spaces as $space) {
        $space_id = $space->id();
        $space_urls = [];

        // Build URLs for each language.
        foreach ($language_codes as $langcode) {
          $prefix = !empty($language_prefixes[$langcode]) ? '/' . $language_prefixes[$langcode] : '';
          $space_urls[$langcode] = $base_url . $prefix . '/nodehive-api/v1/space/' . $space_id;
        }

        $available_spaces[] = [
          'id' => $space_id,
          'name' => $space->label(),
        ];

        $available_spaces_with_urls[] = [
          'id' => $space_id,
          'name' => $space->label(),
          'urls' => $space_urls,
        ];
      }

      // Build endpoint documentation.
      $endpoints = [
        [
          'name' => 'Menu API',
          'method' => 'GET',
          'available_menus' => $available_menus,
        ],
        [
          'name' => 'Spaces API',
          'method' => 'GET',
          'available_spaces' => $available_spaces_with_urls,
        ],
      ];

      // Build response data.
      $response_data = [
        'host' => $request->getHost(),
        'available_languages' => $language_codes,
        'available_spaces' => $available_spaces,
        'endpoints' => $endpoints,
      ];

      // Create response with envelope.
      $cache_metadata = new CacheableMetadata();
      $cache_metadata->addCacheContexts(['user.permissions', 'languages']);
      $cache_metadata->addCacheTags(['config:core.extension', 'config:system.menu_list', 'nodehive_space_list']);

      $response = $this->apiSuccess($response_data, $cache_metadata);

      // Add cache tags for all menus.
      foreach ($menus as $menu) {
        $response->addCacheableDependency($menu);
      }

      // Add cache tags for all spaces.
      foreach ($spaces as $space) {
        $response->addCacheableDependency($space);
      }

      return $response;
    }
    catch (\Exception $e) {
      $this->getLogger('nodehive_public_api')->error(
        'Error generating API index: @message',
        ['@message' => $e->getMessage()]
      );

      return $this->apiError(
        (string) $this->t('An error occurred while generating the API index.'),
        500
      );
    }
  }

}
