<?php

namespace Drupal\nodehive_jsonapi_extras_massedit\Form;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteBuilderInterface;
use Drupal\jsonapi\ResourceType\ResourceTypeRepository;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a form for mass enabling/disabling JSON:API resources.
 */
class ResourceMassEditForm extends FormBase {

  /**
   * The JSON:API resource type repository.
   *
   * @var \Drupal\jsonapi\ResourceType\ResourceTypeRepository
   */
  protected $resourceTypeRepository;

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

  /**
   * The route builder.
   *
   * @var \Drupal\Core\Routing\RouteBuilderInterface
   */
  protected $routeBuilder;

  /**
   * Constructs a ResourceMassEditForm object.
   *
   * @param \Drupal\jsonapi\ResourceType\ResourceTypeRepository $resource_type_repository
   *   The JSON:API resource type repository.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
   *   The route builder.
   */
  public function __construct(ResourceTypeRepository $resource_type_repository, EntityTypeManagerInterface $entity_type_manager, RouteBuilderInterface $route_builder) {
    $this->resourceTypeRepository = $resource_type_repository;
    $this->entityTypeManager = $entity_type_manager;
    $this->routeBuilder = $route_builder;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('jsonapi.resource_type.repository'),
      $container->get('entity_type.manager'),
      $container->get('router.builder')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'nodehive_jsonapi_extras_massedit_resource_mass_edit_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['#attached']['library'][] = 'core/drupal.tableselect';

    $form['description'] = [
      '#markup' => '<p>' . $this->t('Use this form to quickly enable or disable JSON:API resource types. Disabled resources will not be available via the JSON:API.') . '</p>',
    ];

    $form['filter'] = [
      '#type' => 'details',
      '#title' => $this->t('Filter'),
      '#open' => TRUE,
    ];

    $form['filter']['entity_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Filter by entity type'),
      '#options' => $this->getEntityTypeOptions(),
      '#empty_option' => $this->t('- All -'),
      '#ajax' => [
        'callback' => '::updateResourceTable',
        'wrapper' => 'resource-table-wrapper',
        'method' => 'replace',
        'effect' => 'fade',
      ],
    ];

    $form['filter']['status_filter'] = [
      '#type' => 'select',
      '#title' => $this->t('Filter by status'),
      '#options' => [
        'all' => $this->t('All'),
        'enabled' => $this->t('Enabled'),
        'disabled' => $this->t('Disabled'),
      ],
      '#default_value' => 'all',
      '#ajax' => [
        'callback' => '::updateResourceTable',
        'wrapper' => 'resource-table-wrapper',
        'method' => 'replace',
        'effect' => 'fade',
      ],
    ];

    $form['table_wrapper'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'resource-table-wrapper'],
    ];

    $entity_type_filter = $form_state->getValue('entity_type');
    $status_filter = $form_state->getValue('status_filter') ?: 'all';
    $resources = $this->getResources($entity_type_filter, $status_filter);

    $form['table_wrapper']['resources'] = [
      '#type' => 'tableselect',
      '#header' => [
        'resource_type' => $this->t('Resource Type'),
        'entity_type' => $this->t('Entity Type'),
        'bundle' => $this->t('Bundle'),
        'status' => $this->t('Current Status'),
      ],
      '#options' => $resources,
      '#empty' => $this->t('No resources found.'),
    ];

    $form['actions'] = [
      '#type' => 'actions',
    ];

    $form['actions']['enable'] = [
      '#type' => 'submit',
      '#value' => $this->t('Enable selected'),
      '#submit' => ['::submitEnableResources'],
      '#button_type' => 'primary',
    ];

    $form['actions']['disable'] = [
      '#type' => 'submit',
      '#value' => $this->t('Disable selected'),
      '#submit' => ['::submitDisableResources'],
    ];

    $form['actions']['enable_all'] = [
      '#type' => 'submit',
      '#value' => $this->t('Enable all'),
      '#submit' => ['::submitEnableAll'],
    ];

    $form['actions']['disable_all'] = [
      '#type' => 'submit',
      '#value' => $this->t('Disable all'),
      '#submit' => ['::submitDisableAll'],
    ];

    return $form;
  }

  /**
   * AJAX callback to update the resource table.
   */
  public function updateResourceTable(array &$form, FormStateInterface $form_state) {
    return $form['table_wrapper'];
  }

  /**
   * Gets all entity type options.
   *
   * @return array
   *   An array of entity type labels keyed by entity type ID.
   */
  protected function getEntityTypeOptions() {
    $options = [];
    foreach ($this->resourceTypeRepository->all() as $resource_type) {
      $entity_type_id = $resource_type->getEntityTypeId();
      if (!isset($options[$entity_type_id])) {
        $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
        $options[$entity_type_id] = $entity_type->getLabel();
      }
    }
    asort($options);
    return $options;
  }

  /**
   * Gets all resources for the table.
   *
   * @param string|null $entity_type_filter
   *   Optional entity type ID to filter by.
   * @param string $status_filter
   *   Status filter: 'all', 'enabled', or 'disabled'.
   *
   * @return array
   *   An array of resources for the table.
   */
  protected function getResources($entity_type_filter = NULL, $status_filter = 'all') {
    $resources = [];
    $config_storage = $this->entityTypeManager->getStorage('jsonapi_resource_config');

    foreach ($this->resourceTypeRepository->all() as $resource_type) {
      $entity_type_id = $resource_type->getEntityTypeId();
      $bundle = $resource_type->getBundle();

      // Apply entity type filter if set.
      if ($entity_type_filter && $entity_type_id !== $entity_type_filter) {
        continue;
      }

      $config_id = sprintf('%s--%s', $entity_type_id, $bundle);
      $config = $config_storage->load($config_id);
      $disabled = $config && $config->get('disabled') ? TRUE : FALSE;

      // Apply status filter.
      if ($status_filter === 'enabled' && $disabled) {
        continue;
      }
      if ($status_filter === 'disabled' && !$disabled) {
        continue;
      }

      $resources[$config_id] = [
        'resource_type' => $resource_type->getTypeName(),
        'entity_type' => $entity_type_id,
        'bundle' => $bundle,
        'status' => [
          'data' => [
            '#markup' => $disabled ?
            '<span style="color: red;">' . $this->t('Disabled') . '</span>' :
            '<span style="color: green;">' . $this->t('Enabled') . '</span>',
          ],
        ],
      ];
    }

    return $resources;
  }

  /**
   * Submit handler for enabling selected resources.
   */
  public function submitEnableResources(array &$form, FormStateInterface $form_state) {
    $selected = array_filter($form_state->getValue('resources'));
    $this->setResourcesStatus($selected, FALSE);
    $this->messenger()->addStatus($this->t('Enabled @count resource(s).', ['@count' => count($selected)]));
  }

  /**
   * Submit handler for disabling selected resources.
   */
  public function submitDisableResources(array &$form, FormStateInterface $form_state) {
    $selected = array_filter($form_state->getValue('resources'));
    $this->setResourcesStatus($selected, TRUE);
    $this->messenger()->addStatus($this->t('Disabled @count resource(s).', ['@count' => count($selected)]));
  }

  /**
   * Submit handler for enabling all resources.
   */
  public function submitEnableAll(array &$form, FormStateInterface $form_state) {
    $entity_type_filter = $form_state->getValue('entity_type');
    $status_filter = $form_state->getValue('status_filter') ?: 'all';
    $resources = $this->getResources($entity_type_filter, $status_filter);
    $this->setResourcesStatus(array_keys($resources), FALSE);
    $count = count($resources);
    $this->messenger()->addStatus($this->t('Enabled @count resource(s).', ['@count' => $count]));
  }

  /**
   * Submit handler for disabling all resources.
   */
  public function submitDisableAll(array &$form, FormStateInterface $form_state) {
    $entity_type_filter = $form_state->getValue('entity_type');
    $status_filter = $form_state->getValue('status_filter') ?: 'all';
    $resources = $this->getResources($entity_type_filter, $status_filter);
    $this->setResourcesStatus(array_keys($resources), TRUE);
    $count = count($resources);
    $this->messenger()->addStatus($this->t('Disabled @count resource(s).', ['@count' => $count]));
  }

  /**
   * Sets the status of resources.
   *
   * @param array $resource_ids
   *   An array of resource config IDs.
   * @param bool $disabled
   *   TRUE to disable, FALSE to enable.
   */
  protected function setResourcesStatus(array $resource_ids, $disabled) {
    if (empty($resource_ids)) {
      return;
    }

    $config_storage = $this->entityTypeManager->getStorage('jsonapi_resource_config');

    foreach ($resource_ids as $config_id) {
      $config = $config_storage->load($config_id);

      // Create new config if it doesn't exist.
      if (!$config) {
        $parts = explode('--', $config_id);
        $config = $config_storage->create([
          'id' => $config_id,
          'resourceType' => $parts[0],
          'disabled' => $disabled,
        ]);
      }
      else {
        $config->set('disabled', $disabled);
      }

      $config->save();
    }

    // Clear cache to ensure changes take effect.
    $this->routeBuilder->rebuild();
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Default submit handler - not used as we have custom submit handlers.
  }

}
