<?php

namespace Tests\Unit\Services;

use App\Facades\Settings;
use App\Models\ExternalServiceUsage;
use App\Services\OpenAI;
use Illuminate\Support\Facades\Http;
use Mockery;
use Tests\TenantTestCase;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleOffer;

class OpenAITest extends TenantTestCase

{
    public function testCanGenerateDescriptionOnImportReturnsCorrectValue()
    {
        Settings::shouldReceive('get')
            ->once()
            ->with('open-ai-generate-description-on-vehicle-imported')
            ->andReturn(true);

        $service = new OpenAI(Mockery::mock(ExternalServiceUsage::class));
        $this->assertTrue($service->canGenerateDescriptionOnImport());
    }

    public function testGetDescriptionReturnsEmptyWhenApiKeyMissing()
    {
        Settings::shouldReceive('get')
            ->with('open-ai-api_key')
            ->andReturn('');

        $service = new OpenAI(Mockery::mock(ExternalServiceUsage::class));
        $vehicle = Mockery::mock(Vehicle::class);

        $this->assertSame('', $service->getDescription($vehicle));
    }

    public function testGetDescriptionReturnsEmptyWhenApiFails()
    {
        Settings::shouldReceive('get')->with('open-ai-api_key')->andReturn('fake-key');
        Settings::shouldReceive('get')->with('open-ai-user_prompt')->andReturn('Describe this vehicle');
        Settings::shouldReceive('get')->with('open-ai-system_prompt')->andReturn('You are a vehicle expert.');
        Settings::shouldReceive('get')->with('open-ai-generate-description-use-tech-data')->andReturn(true);
        Settings::shouldReceive('get')->with('open-ai-generate-description-use-equipment')->andReturn(true);

        config(['services.open-ai.model' => 'gpt-4']);
        config(['services.open-ai.endpoint' => 'https://api.openai.com/v1/']);

        $vehicle = new Vehicle(['auto_trader_id' => null]);

        $usageMock = Mockery::mock(ExternalServiceUsage::class);
        $usageMock->shouldReceive('logUsage')->once();

        Http::fake([
            'https://api.openai.com/v1/chat/completions' => Http::response([], 500),
        ]);

        $service = new OpenAI($usageMock);
        $this->assertSame('', $service->getDescription($vehicle));
    }

    public function testGetDescriptionReturnsTextOnSuccess()
    {
        Settings::shouldReceive('get')->with('open-ai-api_key')->andReturn('valid-api-key');
        Settings::shouldReceive('get')->with('open-ai-user_prompt')->andReturn('Describe this vehicle');
        Settings::shouldReceive('get')->with('open-ai-system_prompt')->andReturn('You are a vehicle expert.');
        Settings::shouldReceive('get')->with('open-ai-generate-description-use-tech-data')->andReturn(true);
        Settings::shouldReceive('get')->with('open-ai-generate-description-use-equipment')->andReturn(true);

        config(['services.open-ai.model' => 'gpt-4']);
        config(['services.open-ai.endpoint' => 'https://api.openai.com/v1/']);

        $vehicle = new Vehicle(['auto_trader_id' => null]);

        $usageMock = Mockery::mock(ExternalServiceUsage::class);
        $usageMock->shouldReceive('logUsage')->once();

        Http::fake([
            'https://api.openai.com/v1/chat/completions' => Http::response([
                'choices' => [
                    ['message' => ['content' => 'Hello world!']]
                ]
            ], 200)
        ]);

        $service = new OpenAI($usageMock);
        $response = $service->getDescription($vehicle);

        $this->assertSame('Hello world!', $response);
    }

    public function testGetVehicleOfferSpecsReturnsCorrectData()
    {
        $usageService = Mockery::mock(ExternalServiceUsage::class);
        $service = new OpenAI($usageService);

        $vehicleOffer = VehicleOffer::factory()->create();
        $vehicleOffer->setRelation('make', (object)['name' => 'Tesla']);
        $vehicleOffer->setRelation('model', (object)['name' => 'Model 3']);

        $refMethod = new \ReflectionMethod(OpenAI::class, 'getVehicleOfferSpecs');
        $refMethod->setAccessible(true);

        $result = $refMethod->invoke($service, $vehicleOffer);

        $this->assertIsArray($result);
        $this->assertEquals('Tesla', $result['make']);
        $this->assertEquals('Model 3', $result['model']);
    }

    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }
}
