<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Service;

use Drupal\file\FileInterface;

/**
 * Interface for storing conversion output files in a custom database table.
 *
 * Each row links a media entity + field name + output type to a file entity.
 * Multi-value output types (e.g., subtitle_tracks, segment_thumbnails) are
 * supported via multiple rows sharing the same composite key.
 *
 * @internal Runtime service, not part of the supported contrib extension API.
 */
interface OutputStorageServiceInterface {

  /**
   * Stores an output file for a media entity.
   *
   * Performs an UPSERT for single-value output types. For multi-value types
   * a new row is inserted if the tuple does not already exist.
   *
   * Automatically registers file usage so Drupal does not garbage-collect
   * the referenced file entity.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name on the media entity.
   * @param string $outputType
   *   Output type identifier (e.g., 'mp4', 'webm', 'thumbnail', 'hls').
   * @param \Drupal\file\FileInterface $file
   *   The output file entity.
   */
  public function setOutput(int $mediaId, string $fieldName, string $outputType, FileInterface $file): void;

  /**
   * Gets the latest output file for a given type.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name on the media entity.
   * @param string $outputType
   *   Output type identifier.
   *
   * @return \Drupal\file\FileInterface|null
   *   File entity or NULL if none stored.
   */
  #[\NoDiscard]
  public function getOutput(int $mediaId, string $fieldName, string $outputType): ?FileInterface;

  /**
   * Gets all output files for a given type.
   *
   * Useful for multi-value output types like subtitle_tracks.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name on the media entity.
   * @param string $outputType
   *   Output type identifier.
   *
   * @return array<\Drupal\file\FileInterface>
   *   Array of file entities (empty if none).
   */
  #[\NoDiscard]
  public function getOutputs(int $mediaId, string $fieldName, string $outputType): array;

  /**
   * Gets all output files for a media entity, keyed by output type.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name. Empty string returns all fields.
   *
   * @return array<string, array<\Drupal\file\FileInterface>>
   *   Associative array keyed by output_type, each value an array of files.
   */
  #[\NoDiscard]
  public function getAllOutputs(int $mediaId, string $fieldName = ''): array;

  /**
   * Checks whether a media entity has any stored outputs.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name. Empty string checks all fields.
   *
   * @return bool
   *   TRUE if at least one output exists.
   */
  #[\NoDiscard]
  public function hasOutputs(int $mediaId, string $fieldName = ''): bool;

  /**
   * Gets all media IDs that have at least one stored output.
   *
   * Useful for Drush commands that need to filter converted/unconverted media.
   *
   * @return array<int>
   *   Array of media entity IDs.
   */
  #[\NoDiscard]
  public function getConvertedMediaIds(): array;

  /**
   * Gets all outputs for a media entity in a single query, keyed by type.
   *
   * Loads ALL output rows for the given media entity ID regardless of
   * field name, and groups them by output_type. Each output type maps
   * to a list of associative arrays containing file metadata.
   *
   * This is a batch-optimized alternative to calling getOutputs() or
   * getOutput() multiple times for different output types, avoiding
   * N+1 query patterns.
   *
   * @param int $mediaId
   *   The media entity ID.
   *
   * @return array<string, array<int, array{file_id: int, field_name: string, created: int, file: \Drupal\file\FileInterface|null}>>
   *   Associative array keyed by output_type. Each value is a list of
   *   arrays with keys: 'file_id', 'field_name', 'created', 'file'.
   *   The 'file' key contains the loaded FileInterface or NULL if the
   *   file entity could not be loaded.
   */
  #[\NoDiscard]
  public function getOutputsByMediaId(int $mediaId): array;

  /**
   * Verifies that output file references point to existing files.
   *
   * Checks each output record to confirm the file entity exists and
   * that the physical file on disk is accessible.
   *
   * @param int $mediaId
   *   Optional media entity ID. 0 means check all records.
   *
   * @return array<int, array{row_id: int, media_id: int, field_name: string, output_type: string, file_id: int, expected_uri: string|null, status: string}>
   *   Array of orphaned/problematic records with status:
   *   'missing_entity' if file entity doesn't exist,
   *   'missing_file' if physical file is missing.
   */
  #[\NoDiscard]
  public function verifyOutputFiles(int $mediaId = 0): array;

  /**
   * Deletes a specific orphaned output record.
   *
   * Used by maintenance commands to remove records whose file entity
   * or physical file no longer exists.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name on the media entity.
   * @param string $outputType
   *   Output type identifier.
   * @param int $fileId
   *   The file entity ID.
   */
  public function deleteOrphanedRecord(int $mediaId, string $fieldName, string $outputType, int $fileId): void;

  /**
   * Deletes all output files for a specific type.
   *
   * Also removes file usage references so Drupal can garbage-collect
   * the file entities.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name on the media entity.
   * @param string $outputType
   *   Output type identifier.
   */
  public function deleteOutput(int $mediaId, string $fieldName, string $outputType): void;

  /**
   * Deletes all output files for a media entity.
   *
   * Also removes file usage references.
   *
   * @param int $mediaId
   *   The media entity ID.
   * @param string $fieldName
   *   The source field name. Empty string deletes all fields.
   */
  public function deleteAllOutputs(int $mediaId, string $fieldName = ''): void;

}
