<?php

namespace Tests\Feature;

use App\Http\Middleware\OptimizeUploadedImages;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Response;
use Tests\TestCase;

class ImageUploadOptimizerTest extends TestCase
{
    public function test_png_upload_is_converted_to_smaller_webp_without_changing_dimensions(): void
    {
        $this->assertTrue(extension_loaded('gd'), 'GD must be installed for image optimization.');
        $this->assertTrue(function_exists('imagewebp'), 'GD must include WebP encoding support.');

        $source = tempnam(sys_get_temp_dir(), 'mf-image-source-');
        $this->assertNotFalse($source);

        try {
            $image = imagecreatetruecolor(1200, 800);
            $this->assertNotFalse($image);
            imagefilledrectangle($image, 0, 0, 1199, 799, imagecolorallocate($image, 245, 245, 245));

            for ($x = 0; $x < 1200; $x += 40) {
                $color = imagecolorallocate($image, ($x * 3) % 255, ($x * 7) % 255, ($x * 11) % 255);
                imageline($image, $x, 0, 1199 - $x, 799, $color);
            }

            imagepng($image, $source, 0);
            imagedestroy($image);

            $originalSize = filesize($source);
            $this->assertIsInt($originalSize);

            $request = Request::create('/test-upload', 'POST', [], [], [
                'photo' => new UploadedFile($source, 'customer-photo.png', 'image/png', UPLOAD_ERR_OK, true),
            ]);

            app(OptimizeUploadedImages::class)->handle($request, function (Request $request) use ($originalSize): Response {
                $optimized = $request->file('photo');

                $this->assertNotNull($optimized);
                $this->assertSame('customer-photo.webp', $optimized->getClientOriginalName());
                $this->assertSame('image/webp', $optimized->getMimeType());
                $this->assertLessThan($originalSize, $optimized->getSize());

                $dimensions = getimagesize($optimized->getPathname());
                $this->assertIsArray($dimensions);
                $this->assertSame(1200, $dimensions[0]);
                $this->assertSame(800, $dimensions[1]);

                return new Response('ok');
            });
        } finally {
            @unlink($source);
        }
    }

    public function test_nested_multiple_image_uploads_are_all_converted_to_webp(): void
    {
        $sources = [$this->createJpeg(640, 480), $this->createJpeg(320, 240)];

        try {
            $request = Request::create('/test-upload', 'POST', [], [], [
                'photos' => [
                    new UploadedFile($sources[0], 'front.jpg', 'image/jpeg', UPLOAD_ERR_OK, true),
                    new UploadedFile($sources[1], 'back.jpeg', 'image/jpeg', UPLOAD_ERR_OK, true),
                ],
            ]);

            app(OptimizeUploadedImages::class)->handle($request, function (Request $request): Response {
                $photos = $request->file('photos');

                $this->assertCount(2, $photos);
                $this->assertSame('front.webp', $photos[0]->getClientOriginalName());
                $this->assertSame('back.webp', $photos[1]->getClientOriginalName());
                $this->assertSame('image/webp', $photos[0]->getMimeType());
                $this->assertSame('image/webp', $photos[1]->getMimeType());

                return new Response('ok');
            });
        } finally {
            foreach ($sources as $source) {
                @unlink($source);
            }
        }
    }

    public function test_non_image_upload_is_left_unchanged(): void
    {
        $source = tempnam(sys_get_temp_dir(), 'mf-document-source-');
        $this->assertNotFalse($source);
        file_put_contents($source, 'microfinance document');

        try {
            $request = Request::create('/test-upload', 'POST', [], [], [
                'document' => new UploadedFile($source, 'document.txt', 'text/plain', UPLOAD_ERR_OK, true),
            ]);

            app(OptimizeUploadedImages::class)->handle($request, function (Request $request): Response {
                $document = $request->file('document');

                $this->assertNotNull($document);
                $this->assertSame('document.txt', $document->getClientOriginalName());
                $this->assertSame('text/plain', $document->getMimeType());
                $this->assertSame('microfinance document', file_get_contents($document->getPathname()));

                return new Response('ok');
            });
        } finally {
            @unlink($source);
        }
    }

    private function createJpeg(int $width, int $height): string
    {
        $source = tempnam(sys_get_temp_dir(), 'mf-jpeg-source-');
        $this->assertNotFalse($source);

        $image = imagecreatetruecolor($width, $height);
        $this->assertNotFalse($image);
        imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, imagecolorallocate($image, 90, 140, 190));
        imagejpeg($image, $source, 95);
        imagedestroy($image);

        return $source;
    }
}
