<?php

declare(strict_types=1);

final class MyronMediaAccessibilityActionService
{
    public function __construct(
        private readonly MyronFileRepository $files,
        private readonly MyronVideoAssetRepository $videos,
        private readonly MyronFilesActionService $fileActions,
        private readonly MyronMediaAccessibilityAttachmentRepository $attachments,
    ) {
    }

    /**
     * @param array<string, mixed> $envelope
     * @param array<string, mixed> $metadata
     * @return array<string, mixed>
     */
    public function uploadVideoCaptionsFromEnvelope(
        string $assetId,
        array $envelope,
        array $metadata,
        MyronActionCallerContext $caller
    ): array {
        $assetId = trim($assetId);
        if (!is_array($this->videos->getVideoAssetById($assetId))) {
            throw new RuntimeException('The selected video asset could not be found.');
        }

        $file = $this->fileActions->uploadFromEnvelope($envelope, [
            'asset_class' => 'document',
            'title' => (string) ($metadata['title'] ?? 'Video captions'),
            'description' => (string) ($metadata['description'] ?? 'Caption file for the video asset.'),
            'alt_text' => '',
            'caption' => '',
        ], $caller);

        return $this->attachments->attachOrReplace(
            'video_asset',
            $assetId,
            'captions',
            (string) ($file['id'] ?? ''),
            $this->callerUserId($caller),
            [
                'language' => (string) ($metadata['language'] ?? 'en'),
                'label' => (string) ($metadata['label'] ?? 'English'),
            ]
        );
    }

    /**
     * @return array{assetId:string, deleted:bool}
     */
    public function deleteVideoCaptions(string $assetId, MyronActionCallerContext $caller): array
    {
        $assetId = trim($assetId);
        if ($assetId === '') {
            throw new InvalidArgumentException('assetId is required.');
        }
        $this->attachments->deleteAttachment('video_asset', $assetId, 'captions', true);
        return ['assetId' => $assetId, 'deleted' => true];
    }

    /**
     * @param array<string, mixed> $envelope
     * @param array<string, mixed> $metadata
     * @return array<string, mixed>
     */
    public function uploadAudioTranscriptFromEnvelope(
        string $fileId,
        array $envelope,
        array $metadata,
        MyronActionCallerContext $caller
    ): array {
        $fileId = trim($fileId);
        $audio = $this->files->getFileById($fileId);
        if (!is_array($audio) || (string) ($audio['media_class'] ?? '') !== 'audio') {
            throw new RuntimeException('The selected audio asset could not be found.');
        }

        $file = $this->fileActions->uploadFromEnvelope($envelope, [
            'asset_class' => 'document',
            'title' => (string) ($metadata['title'] ?? 'Audio transcript'),
            'description' => (string) ($metadata['description'] ?? 'Transcript file for the audio asset.'),
            'alt_text' => '',
            'caption' => '',
        ], $caller);

        return $this->attachments->attachOrReplace(
            'audio_file',
            $fileId,
            'transcript',
            (string) ($file['id'] ?? ''),
            $this->callerUserId($caller),
            [
                'language' => (string) ($metadata['language'] ?? 'en'),
                'label' => (string) ($metadata['label'] ?? 'Transcript'),
            ]
        );
    }

    /**
     * @return array{fileId:string, deleted:bool}
     */
    public function deleteAudioTranscript(string $fileId, MyronActionCallerContext $caller): array
    {
        $fileId = trim($fileId);
        if ($fileId === '') {
            throw new InvalidArgumentException('fileId is required.');
        }
        $this->attachments->deleteAttachment('audio_file', $fileId, 'transcript', true);
        return ['fileId' => $fileId, 'deleted' => true];
    }

    private function callerUserId(MyronActionCallerContext $caller): string
    {
        if ($caller->callerType === 'human-session' && trim($caller->callerId) !== '') {
            return trim($caller->callerId);
        }

        throw new RuntimeException('Media accessibility changes require an authenticated user.');
    }
}
