<?php

declare(strict_types=1);

namespace Drupal\Tests\acquia_dam\FunctionalJavascript;

use Drupal\acquia_dam\Entity\ManagedImageField;

/**
 * Test coverage for download and sync feature.
 *
 * @group acquia_dam_functional_javascript
 */
class AcquiaDamDownloadAndSyncAssetTest extends AcquiaDamWebDriverTestBase {

  /**
   * {@inheritdoc}
   */
  protected bool $useOneTimeLoginLinks = FALSE;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->createMediaReferenceField(1);
    // Create user to update image media type and login.
    $user = $this->createUser([
      'administer media types',
      'access media overview',
      'administer media',
      'create page content',
      'edit any page content',
      'administer site configuration',
      'access site reports',
    ]);
    $this->drupalLogin($user);
  }

  /**
   * Creating a media field for the test.
   */
  protected function createMediaReferenceField($cardinality = -1) {
    $this->createEntityReferenceField(
      'node',
      'page',
      'field_acquia_dam',
      'Acquia DAM',
      'media',
      'default:media',
      [],
      $cardinality,
    );
    $display_repository = $this->container->get('entity_display.repository');
    $display_repository->getFormDisplay('node', 'page')
      ->setComponent('field_acquia_dam', [
        'type' => 'media_library_widget',
        'region' => 'content',
      ])->save();
    $display_repository->getViewDisplay('node', 'page', 'default')
      ->setComponent('field_acquia_dam', [
        'type' => 'media_thumbnail',
      ])->save();
  }

  /**
   * Tests the damMediaExistLocally method.
   */
  public function testDamMediaExistLocally(): void {
    $asset_id = 'f2a9c03d-3664-477c-8013-e84504ed5adc';
    $filename = 'An asset with many versions.png';

    // Acquia DAM authorization.
    $this->grantSiteRegistrationToken();
    $this->grantCurrentUserDamToken();

    // Verify the "Download and sync assets" checkbox is not disabled.
    $this->drupalGet('admin/structure/media/manage/acquia_dam_image_asset');
    $this->assertSession()->elementAttributeNotExists('css', 'input[name="source_configuration[download_assets]"]', 'disabled');

    // Create node of type page and add media from acquia DAM.
    $this->drupalGet('node/add/page');
    $this->getSession()->getPage()->fillField('Title', 'Download and sync Media locally');
    $wrapper = $this->assertSession()->elementExists('css', '#field_acquia_dam-media-library-wrapper');
    $wrapper->pressButton('Add media');

    // Wait for media library modal to open.
    $modal = $this->assertSession()->waitForElement('css', '#drupal-modal');
    // Wait for the "Image" link to appear.
    $this->assertSession()->waitForElement('named', ['link', 'Image']);
    $modal->clickLink('Image');
    $this->assertSession()->assertWaitOnAjaxRequest();

    // Select and insert specified image.
    $this->selectAndInsertAsset($asset_id, 'Image', '', FALSE);
    $this->getSession()->switchToIFrame();
    $this->getSession()->getPage()->pressButton('Save');
    $this->assertSession()->waitForText('page Download and sync Media locally has been created.');

    // Verify the "Download and sync assets" checkbox is disabled.
    $this->drupalGet('admin/structure/media/manage/acquia_dam_image_asset');
    $this->assertSession()->elementAttributeContains('css', 'input[name="source_configuration[download_assets]"]', 'disabled', 'disabled');

    // Run batch to sync media locally.
    $this->getSession()->getPage()->pressButton('edit-source-configuration-download-assets-button');

    // Wait for batch to complete.
    $this->assertSession()->waitForText('All assets have been downloaded and synced successfully.');

    // Verify now the "Download and sync assets" checkbox is enabled.
    $this->drupalGet('admin/structure/media/manage/acquia_dam_image_asset');
    $this->getSession()->getPage()->checkField('source_configuration[download_assets]');
    $this->drupalGet('node/1');

    // Validate image rendered local url.
    $expected_uri = "files/dam/m2x3z2j9ou/" . preg_replace('/\s/', '-', $filename);
    $this->assertSession()->elementAttributeContains('css', 'img', 'src', $expected_uri);
    $this->assertSession()->elementAttributeContains('css', 'img', 'loading', 'lazy');
  }

  /**
   * Tests private file access control for DAM assets.
   *
   * This test verifies that DAM assets downloaded to private filesystem
   * are properly protected and only accessible by users with appropriate
   * permissions. It validates the uri_scheme configuration works correctly
   * to enforce access control at the HTTP level.
   */
  public function testPrivateFileAccessControl(): void {
    $asset_id = 'f2a9c03d-3664-477c-8013-e84504ed5adc';
    $filename = 'An asset with many versions.png';

    // Acquia DAM authorization.
    $this->grantSiteRegistrationToken();
    $this->grantCurrentUserDamToken();

    // Configure media type to use PRIVATE uri_scheme.
    // Enable "Download and sync assets" and set uri_scheme to private.
    $this->drupalGet('admin/structure/media/manage/acquia_dam_image_asset');
    $this->getSession()->getPage()->checkField('source_configuration[download_assets]');
    $this->getSession()->getPage()->selectFieldOption('source_configuration[uri_scheme]', 'private');
    $this->getSession()->getPage()->pressButton('Save');
    $this->assertSession()->waitForText('The media type Acquia DAM: Image has been updated.');

    // Create node and add media from Acquia DAM.
    $this->drupalGet('node/add/page');
    $this->getSession()->getPage()->fillField('Title', 'DAM media private file system Test');
    $wrapper = $this->assertSession()->elementExists('css', '#field_acquia_dam-media-library-wrapper');
    $wrapper->pressButton('Add media');

    // Wait for media library modal and select image.
    $modal = $this->assertSession()->waitForElement('css', '#drupal-modal');
    $this->assertSession()->waitForElement('named', ['link', 'Image']);
    $modal->clickLink('Image');
    $this->assertSession()->assertWaitOnAjaxRequest();

    // Select and insert the asset.
    $this->selectAndInsertAsset($asset_id, 'Image', '', FALSE);
    $this->getSession()->switchToIFrame();
    $this->getSession()->getPage()->pressButton('Save');
    $this->assertSession()->waitForText('page Private DAM Media Test has been created.');

    // Validate image rendered local url.
    $this->drupalGet('node/1');
    $expected_uri = "system/files/dam/m2x3z2j9ou/" . preg_replace('/\s/', '-', $filename);
    $this->assertSession()->elementAttributeContains('css', 'img', 'src', $expected_uri);

    // Test authenticated user can access private file
    // through Drupal's file system.
    $media_entity = \Drupal::entityTypeManager()
      ->getStorage('media')
      ->load(1);
    $file_entity = $media_entity->get(ManagedImageField::MANAGED_IMAGE_FIELD_NAME)->entity;
    $file_url = \Drupal::service('file_url_generator')->generateAbsoluteString($file_entity->getFileUri());

    // Unpublish the media entity to test access denial.
    $media_entity->setUnpublished();
    $media_entity->save();
    // Verify access is allowed for user with active session.
    $this->drupalGet($file_url);
    $this->assertSession()->pageTextNotContains('Access denied');
    // Verify access is denied for anonymous user.
    $this->drupalLogout();
    $this->drupalGet($file_url);
    $this->assertSession()->pageTextContains('Access denied');
  }

}
