<?php

declare(strict_types=1);

namespace Drupal\conductor\Hook;

use Drupal\conductor\ConductorHttpApiClient;
use Drupal\conductor\Exception\ConductorCredentialsNotFoundException;
use Drupal\conductor\Repository\DraftRepositoryInterface;
use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountProxyInterface;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\conductor\DraftCleanup;

final readonly class ConductorHooks {

  public function __construct(
    private AccountProxyInterface $currentUser,
    private ConductorHttpApiClient $client,
    private RouteMatchInterface $routeMatch,
    private RequestStack $requestStack,
    private DraftRepositoryInterface $draftRepository,
    private LoggerInterface $logger,
    private DraftCleanup $draftCleanup,
  ) {
  }

  #[Hook('js_settings_alter')]
  public function jsSettingsAlter(array &$settings, AttachedAssetsInterface $assets): void {
    if (!$this->currentUser->hasPermission('use conductor')) {
      return;
    }
    // Load drupalSettings.conductor only in the Canvas editor.
    if (
      ('entity.canvas_page.edit_form' !== $this->routeMatch->getRouteName()) &&
      !str_starts_with($this->routeMatch->getRouteName() ?? '', 'canvas.')
    ) {
      return;
    }

    $settings['conductor'] = [];
    $settings['conductor']['maxDrafts'] = $this->draftRepository->getMaxDrafts();
    $settings['conductor']['usedDrafts'] = $this->draftRepository->getUsedDrafts();

    try {
      $settings['conductor']['accountId'] = $this->client->getAccountId();
      $entityId = $this->getEntityId();
      $entityType = $this->getEntityType();

      if (
        (!is_null($entityId)) &&
        (!is_null($entityType)) &&
        ($draftId = $this->draftRepository->getDraft($entityType, (int) $entityId))
      ) {
        $settings['conductor']['draftId'] = $draftId['draft_id'];
      }
    }
    // Ignore exception if there is no connection.
    catch (GuzzleException) {
      $this->logger->error('Can\'t connect to Conductor API.');
    }
    // This happens when credentials are not set.
    catch (ConductorCredentialsNotFoundException) {
      $this->logger->error('Conductor API connection failed due to credentials are not set. Check the README.md file for more information.');
    }
  }

  #[Hook('entity_delete')]
  public function entityDelete(EntityInterface $entity): void {
    $this->draftRepository->deleteDraft($entity->getEntityTypeId(), (int) $entity->id());
  }

  #[Hook('cron')]
  public function cron(): void {
    // Cleanup unlinked drafts
    $this->draftCleanup->run();
  }

  private function getEntityId(): ?string {
    return $this->routeMatch->getRawParameter('entity') ??
      $this->routeMatch->getRawParameter('canvas_page') ??
      $this->extractEntityIdFromCurrentRequest() ??
      NULL;
  }

  private function getEntityType(): ?string {
    return $this->routeMatch->getRawParameter('entity_type') ??
      $this->extractEntityTypeFromCurrentRequest() ??
      NULL;
  }

  private function extractEntityIdFromCurrentRequest(): ?string {
    $entity_id = NULL;
    $requestUri = $this->requestStack->getCurrentRequest()?->getRequestUri() ?? '';
    if (
      str_starts_with($requestUri, '/canvas/editor/') &&
      $this->routeMatch->getRouteName() === 'canvas.boot.empty'
    ) {
      $parts = explode('/', $requestUri);
      // For `canvas.boot.entity` => '/canvas/editor/{entity_type}/{entity}'.
      $entity_id = $parts[4] ?? NULL;
    }
    return $entity_id;
  }

  private function extractEntityTypeFromCurrentRequest(): ?string {
    $entity_type = NULL;
    $requestUri = $this->requestStack->getCurrentRequest()?->getRequestUri() ?? '';
    if (
      str_starts_with($requestUri, '/canvas/editor/') &&
      $this->routeMatch->getRouteName() === 'canvas.boot.empty'
    ) {
      $parts = explode('/', $requestUri);
      // For `canvas.boot.entity` => '/canvas/editor/{entity_type}/{entity}'.
      $entity_type = $parts[3] ?? NULL;
    }
    return $entity_type;
  }

}
