<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media_image\Service;

use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;

/**
 * Stores expirable access metadata for temporary private image files.
 *
 * @internal Runtime service, not part of the supported contrib extension API.
 */
final class TemporaryFileAccessManager implements TemporaryFileAccessManagerInterface {

  /**
   * Collection name for temporary image access metadata.
   */
  private const string COLLECTION = 'ffmpeg_media_image_temp_file_access';

  /**
   * Constructs a TemporaryFileAccessManager object.
   *
   * @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $keyValueExpirableFactory
   *   The expirable key-value factory.
   */
  public function __construct(
    private readonly KeyValueExpirableFactoryInterface $keyValueExpirableFactory,
  ) {}

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function registerUri(
    string $uri,
    int $mediaId,
    string $fileMime = 'image/jpeg',
    int $ttl = 3600,
  ): void {
    if (!str_starts_with($uri, 'private://')) {
      return;
    }

    $storage = $this->keyValueExpirableFactory->get(self::COLLECTION);
    $key = $this->buildKey($uri);
    $existing = $storage->get($key);

    $mediaIds = [];
    if (is_array($existing) && isset($existing['media_ids']) && is_array($existing['media_ids'])) {
      foreach ($existing['media_ids'] as $existingMediaId) {
        if (is_scalar($existingMediaId) && (int) $existingMediaId > 0) {
          $mediaIds[] = (int) $existingMediaId;
        }
      }
    }

    $mediaIds[] = $mediaId;
    $mediaIds = array_values(array_unique($mediaIds));

    $storage->setWithExpire($key, [
      'media_ids' => $mediaIds,
      'filemime' => $fileMime,
    ], $ttl);
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function getAccessRecord(string $uri): ?array {
    if (!str_starts_with($uri, 'private://')) {
      return NULL;
    }

    $stored = $this->keyValueExpirableFactory
      ->get(self::COLLECTION)
      ->get($this->buildKey($uri));

    if (!is_array($stored)) {
      return NULL;
    }

    $mediaIds = [];
    foreach (($stored['media_ids'] ?? []) as $mediaId) {
      if (is_scalar($mediaId) && (int) $mediaId > 0) {
        $mediaIds[] = (int) $mediaId;
      }
    }

    $mediaIds = array_values(array_unique($mediaIds));
    if ($mediaIds === []) {
      return NULL;
    }

    return [
      'media_ids' => $mediaIds,
      'filemime' => is_string($stored['filemime'] ?? NULL) && $stored['filemime'] !== ''
        ? $stored['filemime']
        : 'image/jpeg',
    ];
  }

  /**
   * Builds the storage key for a URI.
   */
  private function buildKey(string $uri): string {
    return hash('sha256', $uri);
  }

}
