<?php

namespace App\Media;

use Illuminate\Support\Collection;

use App\Media\QuickTime\Atoms\{mdat,moov,Unknown};
use App\Traits\FindQuicktimeAtoms;

// https://developer.apple.com/documentation/quicktime-file-format/quicktime_movie_files

class QuickTime extends Base {
	use FindQuicktimeAtoms;

	private const LOGKEY = 'MFQ';

	private Collection $atoms;

	private const atom_classes = 'App\\Media\\QuickTime\\Atoms\\';

	public function __construct(string $filename,string $type)
	{
		parent::__construct($filename,$type);

		// Parse the atoms
		$this->atoms = $this->get_atoms(self::atom_classes,Unknown::class,0,$this->filesize);
	}

	public function __get(string $key): mixed
	{
		switch ($key) {
			case 'audio_channels':
			case 'audio_codec':
			case 'audio_samplerate':
				return $this->getAudioAtoms()
					->map(fn($item)=>$item->find_atoms(moov\trak\mdia\minf\stbl\stsd::class,1))
					->flatten()
					->map(fn($item)=>$item->{$key})
					->join(',');

			// Signatures are calculated by the sha of the MDAT atom.
			case 'signature':
				$atom = $this->find_atoms(mdat::class,1);

				return $atom->signature;

			// Creation Time is in the MOOV/MVHD atom
			case 'creation_date':
			case 'duration':
			case 'preferred_rate':
			case 'preferred_volume':
			// Height/Width is in the moov/trak/tkhd attom
			case 'height':
			case 'width':
				$atom = $this->find_atoms(moov::class,1);

				return $atom->{$key};

			case 'gps_altitude':
			case 'gps_lat':
			case 'gps_lon':
				$atom = $this->find_atoms(moov::class,1)
					->find_atoms(moov\meta::class,1);

				return $atom->{$key};

			case 'make':
			case 'model':
			case 'software':
				return $this->find_atoms(moov\meta::class,1)->{$key};

			case 'time_scale':
				$atom = $this->find_atoms(moov\mvhd::class,1);

				return $atom->{$key};

			case 'type':
				return parent::__get($key);

			case 'video_codec':
				return $this->getVideoAtoms()
					->map(fn($item)=>$item->find_atoms(moov\trak\mdia\minf\stbl\stsd::class,1))
					->flatten()
					->map(fn($item)=>$item->{$key})
					->join(',');

			case 'video_framerate':
				$atom = $this->getVideoAtoms()
					->map(fn($item)=>$item->find_atoms(moov\trak\mdia\minf\stbl\stts::class,1))
					->pop();

				return $atom->frame_rate($this->time_scale);

			default:
				throw new \Exception('Unknown key: '.$key);
		}
	}

	/**
	 * Find all the audio track atoms
	 *
	 * Audio atoms are in moov/trak/mdia/minf
	 *
	 * @return Collection
	 * @throws \Exception
	 */
	public function getAudioAtoms(): Collection
	{
		return $this->find_atoms(moov\trak\mdia\minf::class)
			->filter(fn($item)=>$item->type==='soun');
	}

	/**
	 * Find all the video track atoms
	 *
	 * Audio atoms are in moov/trak/mdia/minf
	 *
	 * @return Collection
	 * @throws \Exception
	 */
	public function getVideoAtoms(): Collection
	{
		return $this->find_atoms(moov\trak\mdia\minf::class)
			->filter(fn($item)=>$item->type==='vide');
	}
}