<?php

namespace Tests\Feature;

use App\Models\Service;
use App\Models\Slide;
use App\Models\User;
use Illuminate\Foundation\Testing\Concerns\InteractsWithAuthentication;
use Illuminate\Foundation\Testing\Concerns\MakesHttpRequests;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Tests\TestCase;
use ZipArchive;

final class ProBundleExportTest extends TestCase
{
    use InteractsWithAuthentication;
    use MakesHttpRequests;
    use RefreshDatabase;

    public function test_probundle_enthaelt_pro_datei_und_bilder(): void
    {
        Storage::fake('public');

        $user = User::factory()->create();
        $service = Service::factory()->create();

        $filenames = [
            'info-1.jpg',
            'info-2.jpg',
            'info-3.jpg',
        ];

        foreach ($filenames as $index => $filename) {
            Storage::disk('public')->put('slides/'.$filename, 'fake-image-content-'.$index);

            Slide::factory()->create([
                'service_id' => $service->id,
                'type' => 'information',
                'stored_filename' => 'slides/'.$filename,
                'original_filename' => 'Original '.$filename,
                'sort_order' => $index,
            ]);
        }

        $response = $this->actingAs($user)->get(route('services.download-bundle', [
            'service' => $service,
            'blockType' => 'information',
        ]));

        $response->assertOk();
        $response->assertHeader('content-type', 'application/zip');

        $baseResponse = $response->baseResponse;
        if (! $baseResponse instanceof BinaryFileResponse) {
            $this->fail('Es wurde keine Dateiantwort zurückgegeben.');
        }

        $copiedPath = sys_get_temp_dir().'/probundle-test-'.uniqid().'.probundle';
        copy($baseResponse->getFile()->getPathname(), $copiedPath);

        $zip = new ZipArchive;
        $openResult = $zip->open($copiedPath);

        $this->assertTrue($openResult === true);
        $this->assertSame(4, $zip->numFiles);

        $names = [];
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $name = $zip->getNameIndex($i);
            if ($name !== false) {
                $names[] = $name;
            }
        }

        $proEntry = array_values(array_filter($names, fn (string $n) => str_ends_with($n, '.pro')));
        $this->assertCount(1, $proEntry, '.probundle muss genau eine .pro Datei enthalten');
        $this->assertContains('info-1.jpg', $names);
        $this->assertContains('info-2.jpg', $names);
        $this->assertContains('info-3.jpg', $names);

        foreach ($filenames as $index => $filename) {
            $content = $zip->getFromName($filename);
            $this->assertSame('fake-image-content-'.$index, $content, "Bildinhalt von {$filename} muss korrekt sein");
        }

        $proContent = $zip->getFromName($proEntry[0]);
        $this->assertNotFalse($proContent, '.pro Eintrag muss existieren');
        $this->assertGreaterThan(0, strlen($proContent), '.pro Eintrag darf nicht leer sein');

        $zip->close();
        @unlink($copiedPath);
    }

    public function test_ungueltiger_block_type_liefert_422(): void
    {
        $user = User::factory()->create();
        $service = Service::factory()->create();

        $response = $this->actingAs($user)->getJson(route('services.download-bundle', [
            'service' => $service,
            'blockType' => 'ungueltig',
        ]));

        $response->assertStatus(422);
    }

    public function test_probundle_ohne_slides_enthaelt_nur_pro_datei(): void
    {
        $user = User::factory()->create();
        $service = Service::factory()->create();

        $response = $this->actingAs($user)->get(route('services.download-bundle', [
            'service' => $service,
            'blockType' => 'sermon',
        ]));

        $response->assertOk();

        $baseResponse = $response->baseResponse;
        if (! $baseResponse instanceof BinaryFileResponse) {
            $this->fail('Es wurde keine Dateiantwort zurückgegeben.');
        }

        $copiedPath = sys_get_temp_dir().'/probundle-empty-test-'.uniqid().'.probundle';
        copy($baseResponse->getFile()->getPathname(), $copiedPath);

        $zip = new ZipArchive;
        $openResult = $zip->open($copiedPath);

        $this->assertTrue($openResult === true);
        $this->assertSame(1, $zip->numFiles);
        $this->assertTrue(str_ends_with($zip->getNameIndex(0), '.pro'), 'Einziger Eintrag muss .pro Datei sein');
        $zip->close();

        @unlink($copiedPath);
    }
}
