<?php

namespace App\Services;

use App\Models\Service;
use App\Models\ServiceAgendaItem;
use Illuminate\Support\Facades\Storage;
use InvalidArgumentException;
use ProPresenter\Parser\PresentationBundle;
use ProPresenter\Parser\ProBundleWriter;
use ProPresenter\Parser\ProFileGenerator;
use RuntimeException;

class ProBundleExportService
{
    private const ALLOWED_BLOCK_TYPES = ['information', 'moderation', 'sermon'];

    public function __construct(
        private readonly MacroResolutionService $macroResolutionService,
    ) {}

    public function generateBundle(Service $service, string $blockType): string
    {
        if (! in_array($blockType, self::ALLOWED_BLOCK_TYPES, true)) {
            throw new InvalidArgumentException('Ungültiger Blocktyp für .probundle Export.');
        }

        $slides = $service->slides()
            ->where('type', $blockType)
            ->orderBy('sort_order')
            ->get();

        $groupName = ucfirst($blockType);

        return $this->buildBundleFromSlides($slides, $groupName, $service, $blockType);
    }

    public function generateAgendaItemBundle(ServiceAgendaItem $agendaItem): string
    {
        $agendaItem->loadMissing([
            'service',
            'slides',
            'serviceSong.song.arrangements.arrangementLabels.label.songSlides',
        ]);

        $title = $agendaItem->title ?: 'Ablauf-Element';

        if ($agendaItem->serviceSong?->song_id && $agendaItem->serviceSong->song) {
            $song = $agendaItem->serviceSong->song;

            $labelCount = $song->arrangements()
                ->withCount('arrangementLabels')
                ->get()
                ->sum('arrangement_labels_count');

            if ($labelCount === 0) {
                throw new RuntimeException('Song "'.$song->title.'" hat keine Gruppen.');
            }

            $parserSong = app(ProExportService::class)->generateParserSong($song, $agendaItem->service);
            $proFilename = self::safeFilename($song->title).'.pro';

            $bundle = new PresentationBundle($parserSong, $proFilename);
            $bundlePath = sys_get_temp_dir().'/'.uniqid('agenda-song-').'.probundle';
            ProBundleWriter::write($bundle, $bundlePath);

            return $bundlePath;
        }

        $slides = $agendaItem->slides()
            ->whereNull('deleted_at')
            ->orderBy('sort_order')
            ->get();

        return $this->buildBundleFromSlides($slides, $title, $agendaItem->service, 'agenda_item');
    }

    /** @param  \Illuminate\Database\Eloquent\Collection<int, \App\Models\Slide>  $slides */
    private function buildBundleFromSlides($slides, string $groupName, ?Service $service = null, ?string $partType = null): string
    {
        $slideData = [];
        $mediaFiles = [];

        foreach ($slides as $slide) {
            $sourcePath = Storage::disk('public')->path($slide->stored_filename);
            if (! file_exists($sourcePath)) {
                continue;
            }

            $imageFilename = basename($slide->stored_filename);
            $imageContent = file_get_contents($sourcePath);
            if ($imageContent === false) {
                continue;
            }

            $mediaFiles[$imageFilename] = $imageContent;

            $singleSlideData = [
                'media' => $imageFilename,
                'format' => 'JPG',
                'label' => $slide->original_filename,
            ];

            if ($service !== null && $partType !== null) {
                $slideIndex = count($slideData);
                $totalSlides = $slides->count();
                $macros = $this->macroResolutionService->macrosForSlide(
                    $service,
                    $partType,
                    ['index' => $slideIndex, 'total' => $totalSlides, 'label_id' => null],
                );

                if (! empty($macros)) {
                    // ProPresenter parser currently supports one `macro` entry per slide
                    $singleSlideData['macro'] = $macros[0];
                }
            }

            $slideData[] = $singleSlideData;
        }

        $groups = [
            [
                'name' => $groupName,
                'color' => [0, 0, 0, 1],
                'slides' => $slideData,
            ],
        ];

        $arrangements = [
            [
                'name' => 'normal',
                'groupNames' => [$groupName],
            ],
        ];

        $song = ProFileGenerator::generate($groupName, $groups, $arrangements);
        $proFilename = self::safeFilename($groupName).'.pro';

        $bundle = new PresentationBundle($song, $proFilename, $mediaFiles);
        $bundlePath = sys_get_temp_dir().'/'.uniqid('bundle-').'.probundle';
        ProBundleWriter::write($bundle, $bundlePath);

        return $bundlePath;
    }

    private static function safeFilename(string $name): string
    {
        return preg_replace('/[^a-zA-Z0-9äöüÄÖÜß\-_ ]/', '', $name) ?: 'presentation';
    }
}
