<?php

namespace App\Services\Transcoding;

use App\Enums\SongStorageType;
use App\Helpers\Ulid;
use App\Models\Song;
use App\Models\Transcode;
use App\Services\SongStorages\CloudStorage;
use App\Services\SongStorages\CloudStorageFactory;
use Illuminate\Support\Facades\File;

class CloudTranscodingStrategy extends TranscodingStrategy
{
    public function getTranscodeLocation(Song $song, int $bitRate): string
    {
        $storage = CloudStorageFactory::make($song->storage);

        $transcode = $this->findTranscodeBySongAndBitRate($song, $bitRate)
            ?? $this->createTranscode($storage, $song, $bitRate);

        return $storage->getPresignedUrl($transcode->location);
    }

    /**
     * Create a new transcode for the given song at the specified bit rate by performing the following steps:
     * 1. Transcode the song to the specified bit rate and store it temporarily.
     * 2. Upload the transcoded file back to the cloud storage.
     * 3. Store the transcode record in the database.
     * 4. Delete the temporary file.
     */
    private function createTranscode(CloudStorage $storage, Song $song, int $bitRate): Transcode
    {
        $tmpDestination = artifact_path(sprintf('tmp/%s.m4a', Ulid::generate()));

        $this->transcoder->transcode(
            $storage->getPresignedUrl($song->storage_metadata->getPath()),
            $tmpDestination,
            $bitRate,
        );

        $key = sprintf('transcodes/%d/%s.m4a', $bitRate, Ulid::generate());

        try {
            $storage->uploadToStorage($key, $tmpDestination);

            return $this->createOrUpdateTranscode(
                $song,
                $key,
                $bitRate,
                File::hash($tmpDestination),
                File::size($tmpDestination),
            );
        } finally {
            File::delete($tmpDestination);
        }
    }

    public function deleteTranscodeFile(string $location, SongStorageType $storageType): void
    {
        CloudStorageFactory::make($storageType)->deleteFileWithKey(key: $location, backup: false);
    }
}