<?php

namespace Tests\Feature;

use App\Facades\Settings;
use App\ImageSyncServiceHelper;
use App\Jobs\ImportAutosOnShowFilesJob;
use App\Services\AutosOnShow;
use App\Tier;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Storage;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TestCase;

class  AutosOnShowTest extends TestCase
{
    use RefreshDatabase;
    use WithFaker;

    protected $tenancy = true;

    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testNotificationEndpoint()
    {
        Queue::fake();
        Config::set('services.image-sync-auto-imaging-notification_token', 'abc');
        $vehicle = Vehicle::factory()->create();
        $response = $this->postJson(route('tenant.notifications.autos-on-show', tenant('id')), [
            'api_token' => 'abc',
            'vehicleId' => $vehicle->registration_number,
        ], [
            'Authorization' => 'Bearer abc'
        ]);

        Queue::assertPushed(ImportAutosOnShowFilesJob::class);
        $response->assertStatus(200);
    }

    public function testTriggerFetchImages()
    {
        tenant()->update(['tier' => Tier::STANDARD->value]);
        Settings::make([
            'tab' => 'automotive',
            'section' => 'image-sync',
            'group' => 'autos-on-show',
            'name' => 'enabled',
            'config_key' => 'image-sync-auto-imaging-enabled',
            'value' => true,
            'type' => 'boolean',
        ]);
        Storage::fake('media');
        if (empty($this->faker->image)) {
            $this->markTestSkipped('Unable to generate test image');
        }
        Http::fake([
            'https://api.autosonshow.tv/v2/vehicles/*' => $this->response(),
            'https://uat-api.aos.tv/v2/vehicles' => $this->response(),
            'https://api.autosonshow.tv/v2/token' => Http::response(['access_token' => 'foo-baz']),
            'https://uat-api.aos.tv/v2/token' => Http::response(['access_token' => 'foo-baz']),
            '*' => Http::response('Wrong Request', 400),
        ]);
        $vehicle = Vehicle::factory()->create();
        (new ImageSyncServiceHelper())->triggerSync($vehicle);

        $vehicle->refresh();
        $this->assertEquals('http://foo.baz/bar', $vehicle->exterior_video_url);
        $this->assertEquals(1, $vehicle->mediaUses()->count());
    }

    public function testVehicleMissing()
    {
        Config::set('services.image-sync-auto-imaging-notification_token', 'abc');
        $response = $this->postJson(route('tenant.notifications.autos-on-show', tenant('id')), [
            'vehicleId' => 1
        ], [
            'Authorization' => 'Bearer abc'
        ]);

        // 422 disabled to allow logging and deferred processing
        $response->assertStatus(200);
    }

    public function testNoAuthKey()
    {
        Config::set('services.image-sync-auto-imaging-notification_token', 'abc');
        $response = $this->postJson(route('tenant.notifications.autos-on-show', tenant('id')));

        $response->assertStatus(403);
    }

    public function testGetVehicleMedia()
    {
        Http::fake([
            'https://uat-api.aos.tv/v2/vehicles/AB12CDE' => Http::response(['images' => []]),
            'https://uat-api.aos.tv/v2/token' => Http::response(['access_token' => 'abc123']),
        ]);

        Settings::shouldReceive('get')
            ->with('image-sync-auto-imaging-client_id')
            ->andReturn('client-id');
        Settings::shouldReceive('get')
            ->with('image-sync-auto-imaging-client_secret')
            ->andReturn('client-secret');

        $service = new AutosOnShow();
        $response = $service->getVehicleMedia('AB12 CDE');

        $this->assertIsArray($response);
        $this->assertArrayHasKey('images', $response);
    }

    public function testAuthTokenCanBeCached()
    {
        Http::fake([
            'https://uat-api.aos.tv/v2/token' => Http::response(['access_token' => 'cached-token']),
        ]);

        Settings::shouldReceive('get')
            ->with('image-sync-auto-imaging-client_id')
            ->andReturn('client-id');
        Settings::shouldReceive('get')
            ->with('image-sync-auto-imaging-client_secret')
            ->andReturn('client-secret');

        $service = new AutosOnShow();
        $token1 = $this->invokeMethod($service, 'authToken');
        $token2 = $this->invokeMethod($service, 'authToken');

        $this->assertEquals('cached-token', $token1);
        $this->assertEquals('cached-token', $token2);
    }

    public function testEndpointForLiveAndUAT()
    {
        $service = new AutosOnShow();

        Config::set('services.image-sync-auto-imaging-live_api', false);
        $endpoint = $this->invokeMethod($service, 'endpoint', ['vehicles/123']);
        $this->assertStringStartsWith('https://uat-api.aos.tv/v2/', $endpoint);

        Config::set('services.image-sync-auto-imaging-live_api', true);
        $endpoint = $this->invokeMethod($service, 'endpoint', ['/vehicles/123']);
        $this->assertStringStartsWith('https://api.autosonshow.tv/v2/', $endpoint);
    }

    private function invokeMethod(&$object, string $methodName, array $parameters = [])
    {
        $reflection = new \ReflectionClass(get_class($object));

        $method = $reflection->getMethod($methodName);
        $method->setAccessible(true);

        return $method->invokeArgs($object, $parameters);
    }

    private function response()
    {
        return Http::response([
            'videourl' => 'http://foo.baz/bar',
            'images' => [
                ['large' => $this->faker->image]
            ],
        ]);
    }
}
