<?php

namespace Drupal\visitors\Controller;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Controller\ControllerBase;
use Drupal\views\Views;
use Symfony\Component\HttpFoundation\Request;

/**
 * Display Link Controller.
 *
 * Returns the display link for a given view and display.
 */
class DisplayLinkController extends ControllerBase {

  /**
   * Single-action controller.
   */
  public function __invoke(Request $request, string $view_id, string $display_id) {
    $blocks['path'] = [
      '#view_id'      => $view_id,
      '#view_display' => $display_id,
    ];

    // Store AJAX parameters to exclude from sort links in a static variable
    // that can be accessed by our theme preprocessing hook.
    $ajax_params_to_remove = [
      'class',
      '_wrapper_format',
      'ajax_form',
      '_drupal_ajax',
    ];

    $bidirectional_label = $request->query->get('bidirectional_label');
    if ($bidirectional_label) {
      [$source_view_id, $source_display] = $this->extractViewAndDisplayFromClass($request->query->get('class'));
      // Set bidirectional linking information in drupal_static for
      // VisitorsDisplayLink to use.
      $bidirectional_info = &drupal_static('visitors_bidirectional_linking', []);
      $bidirectional_info[$bidirectional_label] = [
        'view_id' => $source_view_id,
        'display_id' => $source_display,
      ];
    }

    // Store these in a static variable for the theme hook.
    $excluded_params = &drupal_static('visitors_excluded_sort_params', []);
    $excluded_params = $ajax_params_to_remove;

    // Get the referrer URL and extract sort/order parameters.
    $referrer = $request->headers->get('referer');
    $referrer_path = '';
    $sort_args = [];

    if ($referrer) {
      $referrer_parts = parse_url($referrer);
      $referrer_path = $referrer_parts['path'] ?? '';

      // Extract query parameters from referrer.
      if (!empty($referrer_parts['query'])) {
        parse_str($referrer_parts['query'], $referrer_query);

        // Check if referrer has sort/order parameters.
        if (isset($referrer_query['order'])) {
          $sort_args['order'] = $referrer_query['order'];
        }
        if (isset($referrer_query['sort'])) {
          $sort_args['sort'] = $referrer_query['sort'];
        }
      }

      $referrer_path_static = &drupal_static('visitors_referrer_path', '');
      $referrer_path_static = $referrer_path;
    }

    // Apply sort parameters from referrer to the view.
    if (!empty($sort_args)) {
      // Load the view manually to apply sorting.
      $view = Views::getView($view_id);
      if ($view && $view->access($display_id)) {
        $view->setDisplay($display_id);

        // Apply the sort parameters to the view.
        if (isset($sort_args['order']) && isset($sort_args['sort'])) {
          $order_field = $sort_args['order'];
          $sort_direction = strtoupper($sort_args['sort']);

          // Set the sort on the view's table style plugin.
          if ($view->display_handler->getPlugin('style') &&
              method_exists($view->display_handler->getPlugin('style'), 'options')) {
            $style_plugin = $view->display_handler->getPlugin('style');
            $style_plugin->active = $order_field;
            $style_plugin->order = $sort_direction;
          }

          // Also set it via the request for the table style to pick up.
          $temp_query = $sort_args;
          $temp_request = $request->duplicate($temp_query);
          $view->setRequest($temp_request);
        }

        // Build the renderable array.
        $rendered = $view->buildRenderable($display_id);
      }
      else {
        // Fallback to normal embed if view access fails.
        $rendered = \views_embed_view($view_id, $display_id);
      }
    }
    else {
      $rendered = \views_embed_view($view_id, $display_id);
    }

    // Set live preview mode to ensure sort links use current route.
    if (isset($rendered['view_build']['#view'])) {
      $view = $rendered['view_build']['#view'];
      $view->live_preview = TRUE;
      if (!empty($referrer_path)) {
        $view->override_path = $referrer_path;
      }
    }

    $settings = NULL;
    $selector = $request->query->get('class');

    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand($selector, $rendered, $settings));

    return $response;
  }

  /**
   * Extract view ID and display ID from the class parameter.
   *
   * The class parameter contains the format:
   *  .view-id-{view_id}.view-display-id-{display_id}
   * This method extracts both the view ID and display ID from this format.
   *
   * @param string|null $class_selector
   *   The class selector string.
   *
   * @return array|null
   *   Array containing [view_id, display_id] if found, null otherwise.
   */
  protected function extractViewAndDisplayFromClass(?string $class_selector): ?array {
    if (empty($class_selector)) {
      return NULL;
    }

    // Extract view ID and display ID from the format:
    // .view-id-{view_id}.view-display-id-{display_id}.
    if (preg_match('/\.view-id-([^.\s]+)\.view-display-id-([^.\s]+)/', $class_selector, $matches)) {
      return [$matches[1], $matches[2]];
    }

    return NULL;
  }

}
