<?php

declare(strict_types=1);

namespace Stream\Infrastructure\Service;

use Stream\Domain\Model\AudioChunk;
use Stream\Domain\Model\TimeDetails;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\File\File;

readonly class AudioSegmentManager
{
    public function __construct(
        private ParameterBagInterface $parameters,
    ) {
    }

    public function generateFileLocation(TimeDetails $timeDetails): string
    {
        /** @var string $projectDirectory */
        $projectDirectory = $this->parameters->get('kernel.project_dir');

        if ($timeDetails->getOneHourAgo() <= $timeDetails->getTargetTime() && $timeDetails->getTargetTime() < $timeDetails->getNow()) {
            $audioFileName = 'now_playing.mp3';
            $audioFileLocation = \sprintf('%s/var/data/logger/%s',
                $projectDirectory,
                $audioFileName
            );
        } else {
            $audioFileName = \sprintf('Air_%s-00-00.mp3',
                $timeDetails->getTargetTime()->format('Y-m-d_H'),
            );

            $audioFileLocation = \sprintf('%s/var/data/recordings/%s',
                $projectDirectory,
                $audioFileName
            );
        }

        return $audioFileLocation;
    }

    /**
     * @throws \Exception
     */
    public function extractAudioChunk(TimeDetails $timeDetails, string $audioFileLocation): AudioChunk
    {
        $requestedChunk = $this->getChunkIndex($timeDetails->getTargetTime());

        $startByte = 0;
        $audioFile = new File($audioFileLocation);
        $totalFileSize = $audioFile->getSize();
        if ($timeDetails->getOneHourAgo() <= $timeDetails->getTargetTime() && $timeDetails->getTargetTime() < $timeDetails->getNow()) {
            $chunkSize = 5120000;
            $startByte += 298666;
        } else {
            $chunkSize = (int) ceil($totalFileSize / 30);
        }

        $startByte += ($requestedChunk * $chunkSize);
        $endByte = min($startByte + $chunkSize - 1, $totalFileSize - 1);

        if ($startByte > $totalFileSize) {
            throw new \Exception('Invalid chunk requested!');
        }

        /** @var resource $handle */
        $handle = fopen($audioFileLocation, 'r');
        /** @var int<1, max> $bytesToRead */
        $bytesToRead = $endByte - $startByte + 1;

        fseek($handle, $startByte);
        /** @var string $audioContent */
        $audioContent = fread($handle, $bytesToRead);
        fclose($handle);

        return new AudioChunk(
            $audioContent,
            $audioFile->getFilename(),
            $startByte,
            $endByte,
            $totalFileSize
        );
    }

    private function getChunkIndex(\DateTime $time): int
    {
        $minutes = (int) $time->format('i');

        if ($minutes === 0) {
            return $minutes;
        }

        return intdiv($minutes, 2);
    }
}
