<?php

declare(strict_types=1);

namespace Drupal\canvas\Plugin\Adapter;

use Drupal\canvas\PropExpressions\StructuredData\EvaluationResult;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\file\FileInterface;
use Drupal\image\Entity\ImageStyle;
use Drupal\image\ImageStyleInterface;

#[Adapter(
  id: self::PLUGIN_ID,
  label: new TranslatableMarkup('Apply image style'),
  inputs: [
    'image' => [
      'type' => 'object',
      // @todo Make `width` and `height` required?
      'required' => ['src'],
      'properties' => [
        'src' => [
          'title' => 'Original image stream wrapper URI',
          '$ref' => 'json-schema-definitions://canvas.module/stream-wrapper-image-uri',
        ],
        'width' => [
          'title' => 'Original image width',
          'type' => 'integer',
        ],
        'height' => [
          'title' => 'Original image height',
          'type' => 'integer',
        ],
        'alt' => [
          'title' => 'Original image alternative text',
          'type' => 'string',
        ],
      ],
    ],
    'imageStyle' => ['type' => 'string', '$ref' => 'json-schema-definitions://canvas.module/config-entity-id'],
  ],
  requiredInputs: ['image'],
  output: ['type' => 'object', '$ref' => 'json-schema-definitions://canvas.module/image'],
)]
final class ImageAndStyleAdapter extends AdapterBase implements ContainerFactoryPluginInterface {

  use EntityTypeManagerDependentAdapterTrait;

  public const string PLUGIN_ID = 'image_apply_style';

  /**
   * @var array{src:string, alt: string, width:integer, height:integer}
   */
  protected array $image;
  protected string $imageStyle;

  public function adapt(): EvaluationResult {
    $adaptation_cacheability = new CacheableMetadata();

    $files = $this->entityTypeManager
      ->getStorage('file')
      ->loadByProperties(['filename' => urldecode(basename($this->image['src']))]);
    $image = reset($files);
    if (!$image instanceof FileInterface) {
      throw new \Exception('No image file found');
    }
    $adaptation_cacheability->addCacheableDependency($image);

    $image_style = ImageStyle::load($this->imageStyle);
    if ($image_style instanceof ImageStyleInterface) {
      $src = $image_style->buildUrl((string) $image->getFileUri());
      $dimensions = ['width' => $this->image['width'], 'height' => $this->image['height']];
      $image_style->transformDimensions($dimensions, $this->image['src']);
      ['width' => $width, 'height' => $height] = $dimensions;
    }
    else {
      $src = $image->createFileUrl(FALSE);
      // An absolute URL was generated, so a different one must be generated per
      // site served by this Drupal instance.
      // @see \Drupal\Core\Cache\Context\SiteCacheContext
      $adaptation_cacheability->addCacheContexts(['url.site']);
      $height = $this->image['height'];
      $width = $this->image['width'];
    }

    return new EvaluationResult(
      [
        'src' => $src,
        'alt' => $this->image['alt'],
        'width' => $width,
        'height' => $height,
      ],
      $adaptation_cacheability,
    );
  }

}
