<?php

namespace Tests\Unit;

use App\Contracts\FaceSwapDriverInterface;
use App\Services\FaceSwapManager;
use App\Services\FaceSwap\MockDriver;
use App\Services\FaceSwap\SegmindDriver;
use App\UserFacePhoto;
use App\VirtualTryonResult;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Tests\RefreshDatabaseWithoutSeeds;
use Tests\TestCase;

class FaceSwapManagerTest extends TestCase
{
    use RefreshDatabaseWithoutSeeds;

    protected function setUp(): void
    {
        parent::setUp();

        if (!extension_loaded('gd')) {
            $this->markTestSkipped('GD extension required');
        }

        Storage::fake('tryon_local');
        Storage::fake('product_images');
    }

    protected function createTestResult(): VirtualTryonResult
    {
        $user = \App\User::create([
            'name' => 'Test',
            'email' => 'test-manager-' . rand(1000, 9999) . '@example.com',
            'password' => bcrypt('password'),
        ]);

        $product = \App\Product::create([
            'name' => 'Test Product',
            'code' => 'MGR-TEST-' . rand(1000, 9999),
            'slug' => 'mgr-test-' . rand(1000, 9999),
            'image' => 'manager-test.jpg',
            'type' => 1,
            'status' => 1,
            'is_activated' => 1,
            'is_deleted' => 0,
        ]);

        $photo = UserFacePhoto::create([
            'user_id' => $user->id,
            'file_path' => 'face-photos/' . $user->id . '/face.jpg',
            'storage_path' => 'face-photos/' . $user->id . '/face.jpg',
            'is_default' => true,
        ]);

        Storage::disk('tryon_local')->put($photo->storage_path, $this->createMinimalJpeg());
        Storage::disk('product_images')->put('manager-test.jpg', $this->createMinimalJpeg());

        $result = new VirtualTryonResult();
        $result->code = 'mgr-test-' . rand(1000, 9999);
        $result->user_id = $user->id;
        $result->fill([
            'product_id' => $product->id,
            'face_photo_id' => $photo->id,
            'source_image' => 'manager-test.jpg',
            'status' => 'pending',
            'expires_at' => now()->addDays(90),
        ]);
        $result->save();

        return $result;
    }

    protected function createMinimalJpeg(): string
    {
        $img = imagecreatetruecolor(100, 100);
        imagefilledrectangle($img, 0, 0, 100, 100, imagecolorallocate($img, 200, 200, 200));
        ob_start();
        imagejpeg($img, null, 85);
        $data = ob_get_clean();
        imagedestroy($img);
        return $data;
    }

    public function test_mock_driver_swap_completes_successfully()
    {
        $manager = new FaceSwapManager(new MockDriver());
        $result = $this->createTestResult();

        $manager->swap($result);

        $result->refresh();
        $this->assertEquals('completed', $result->status);
        $this->assertNotNull($result->result_image);
        Storage::disk('tryon_local')->assertExists($result->result_image);
    }

    public function test_segmind_driver_swap_completes_successfully()
    {
        config([
            'faceswap.drivers.segmind.api_url' => 'https://api.segmind.com/v1/faceswap-v4',
            'faceswap.drivers.segmind.api_key' => 'test-key',
            'faceswap.drivers.segmind.timeout' => 90,
        ]);

        Http::fake([
            'api.segmind.com/*' => Http::response($this->createMinimalJpeg(), 200, [
                'Content-Type' => 'image/jpeg',
            ]),
        ]);

        $manager = new FaceSwapManager(new SegmindDriver());
        $result = $this->createTestResult();

        $manager->swap($result);

        $result->refresh();
        $this->assertEquals('completed', $result->status);
        Storage::disk('tryon_local')->assertExists($result->result_image);
    }

    public function test_driver_failure_keeps_processing_until_queue_attempts_are_exhausted()
    {
        $failingDriver = new class implements FaceSwapDriverInterface {
            public function process(string $faceImageData, string $productImageData): string
            {
                throw new \Exception('API exploded');
            }
        };

        $manager = new FaceSwapManager($failingDriver);
        $result = $this->createTestResult();

        try {
            $manager->swap($result);
        } catch (\Exception $e) {
            // Expected
        }

        $result->refresh();
        $this->assertEquals('processing', $result->status);
    }

    public function test_cancelled_result_is_skipped()
    {
        $manager = new FaceSwapManager(new MockDriver());
        $result = $this->createTestResult();
        $result->update(['status' => 'cancelled']);

        $manager->swap($result);

        $result->refresh();
        $this->assertEquals('cancelled', $result->status);
    }

    public function test_driver_resolved_from_container()
    {
        config(['faceswap.driver' => 'mock']);

        $driver = $this->app->make(FaceSwapDriverInterface::class);
        $this->assertInstanceOf(MockDriver::class, $driver);
    }

    public function test_driver_resolved_as_segmind_from_container()
    {
        config(['faceswap.driver' => 'segmind']);

        $driver = $this->app->make(FaceSwapDriverInterface::class);
        $this->assertInstanceOf(SegmindDriver::class, $driver);
    }

    public function test_manager_resolved_from_container_with_injected_driver()
    {
        config(['faceswap.driver' => 'mock']);

        $manager = $this->app->make(FaceSwapManager::class);
        $this->assertInstanceOf(FaceSwapManager::class, $manager);
    }
}
