<?php

namespace Tests\Unit;

use App\Console\Commands\RecreateVehicleSlugs;
use App\Facades\Settings;
use Carbon\Carbon;
use App\VehicleRepository;
use Database\Seeders\Global\OpelGrandlandSeeder;
use Database\Seeders\Global\OpelVanSeeder;
use Database\Seeders\Tenant\AutomotiveSettingSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Bus;
use Mtc\ContentManager\Facades\Media;
use Mtc\ContentManager\Models\Media as MediaModel;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\Enquiry;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehiclePriceHistory;
use Mtc\MercuryDataModels\ResourceView;
use Tests\TenantTestCase;

class VehicleTest extends TenantTestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testVehicleHasImages()
    {
        Bus::fake();
        $this->seed(AutomotiveSettingSeeder::class);

        $vehicle = Vehicle::factory()->create();
        $media = MediaModel::factory(3)->create();

        Media::setUsesForModel($media->pluck('id')->toArray(), $vehicle);

        $this->assertEquals(3, $vehicle->mediaUses()->count());
    }


    public function testVehicleSlug()
    {
        $this->seed(AutomotiveSettingSeeder::class);
        Settings::update('automotive-vehicles-url_building_format', 'vrm-make-model');
        $make = VehicleMake::factory()->create(['name' => 'BMW']);
        $model = VehicleModel::factory()->create(['name' => 'i3']);
        $vehicle = Vehicle::factory()->make([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'registration_number' => 'foo',
        ]);
        $vehicle->slug = null;
        $vehicle->save();

        $this->assertEquals('foo-bmw-i3', $vehicle->slug);

        Settings::update('automotive-vehicles-url_building_format', 'title');
        $vehicle2 = Vehicle::factory()->make(['title' => 'Hello my Car']);
        $vehicle2->slug = null;
        $vehicle2->save();
        $this->assertEquals('hello-my-car', $vehicle2->slug);

        Settings::update('automotive-vehicles-url_building_format', 'uuid');
        $vehicle3 = Vehicle::factory()->make(['uuid' => 'baz']);
        $vehicle3->slug = null;
        $vehicle3->save();
        $this->assertEquals('baz', $vehicle3->slug);
    }

    public function testSearchContentSetWhenSaving()
    {
        $make = VehicleMake::factory()->create(['name' => 'bmw']);
        $model = VehicleModel::factory()->create(['name' => '330i']);
        $fuelType = FuelType::factory()->create(['name' => 'Petrol']);
        $bodyStyle = BodyStyleType::factory()->create(['name' => 'Coupe']);
        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'fuel_type_id' => $fuelType->id,
            'body_style_id' => $bodyStyle->id,
            'derivative' => 'e92 Petrol Coupe',
            'registration_number' => 'AC69 DDE',
            'description' => '<p> hello world</p>',
            'colour' => 'black',
            'manufacture_year' => 2007,
        ]);

        $this->assertStringContainsString('bmw', $vehicle->search_content);
        $this->assertStringContainsString('330i', $vehicle->search_content);
        $this->assertStringContainsString('petrol', $vehicle->search_content);
        $this->assertStringContainsString('e92', $vehicle->search_content);
        $this->assertStringContainsString('AC69', $vehicle->search_content);
    }

    public function testOriginalPriceUpdatesOnPriceChange()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'type' => 'bool',
            'value' => true,
            'config_key' => 'vehicles-price-change-updates-original-price'
        ]);

        $vehicle = Vehicle::factory()->create(['price' => 123, 'original_price' => null]);

        $this->assertDatabaseCount(VehiclePriceHistory::class, 1);
        $this->assertNull($vehicle->original_price);
        $vehicle->update(['price' => 200]);
        $this->assertNull($vehicle->original_price);
        $this->assertDatabaseCount(VehiclePriceHistory::class, 2);
        $vehicle->update(['price' => 140]);
        $this->assertEquals(200, $vehicle->original_price);
        $this->assertDatabaseCount(VehiclePriceHistory::class, 3);
        $vehicle->update(['price' => 120]);
        $this->assertEquals(200, $vehicle->original_price);
        $this->assertDatabaseCount(VehiclePriceHistory::class, 4);
        $vehicle->update(['price' => '120']);
        $this->assertEquals(200, $vehicle->original_price);
        $this->assertDatabaseCount(VehiclePriceHistory::class, 4);
        $vehicle->update(['price' => 120]);
        $this->assertEquals(200, $vehicle->original_price);
        $this->assertDatabaseCount(VehiclePriceHistory::class, 4);

        $vehicle->update(['price' => 200]);
        $this->assertNull($vehicle->original_price);
        $this->assertDatabaseCount(VehiclePriceHistory::class, 5);
    }

    public function testOpelModelSeeder()
    {
        $make = \App\Master\Models\VehicleMake::query()->create([
            'slug' => 'opel',
            'name' => 'Opel',
        ]);
        $this->seed(OpelVanSeeder::class);
        $this->seed(OpelGrandlandSeeder::class);
        $this->assertCount(4, \App\Master\Models\VehicleModel::query()->where('make_id', $make->id)->get());
        $this->assertCount(1, \App\Master\Models\VehicleModel::query()->where('slug', 'combo')->get());
        $this->assertCount(1, \App\Master\Models\VehicleModel::query()->where('slug', 'movano')->get());
        $this->assertCount(1, \App\Master\Models\VehicleModel::query()->where('slug', 'vivaro')->get());
        $this->assertCount(1, \App\Master\Models\VehicleModel::query()->where('slug', 'grandland')->get());
    }

    public function testUniqueSlug()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-update-vehicle-slug',
            'value' => 'boolean',
            'type' => true,

        ]);

        // set initial vehicle with slug foo
        Vehicle::factory()->create([
            'title' => 'foo',
        ]);

        $this->assertCount(1, Vehicle::query()->where('slug', 'foo')->get());


        // create with duplicate slug
        $vehicle_one = Vehicle::factory()->create([
            'title' => 'foo',
        ]);

        // assert that new vehicle got a different slug
        $this->assertNotEquals('foo', Vehicle::query()->find($vehicle_one->id)->slug);

        // save with duplicate slug
        $vehicle_two = new Vehicle();
        $vehicle_two->title = 'foo';
        $vehicle_two->slug = 'foo';
        $vehicle_two->save();

        // assert that new vehicle got a different slug
        $this->assertNotEquals('foo', Vehicle::query()->find($vehicle_two->id)->slug);

        // update to duplicate slug
        $vehicle_three = Vehicle::factory()->create([
            'title' => 'foo',
        ]);
        $vehicle_three->update([
            'slug' => 'foo',
        ]);

        // assert that updated vehicle got a different slug
        $this->assertNotEquals('foo', Vehicle::query()->find($vehicle_three->id)->slug);

        $this->assertCount(1, Vehicle::query()->where('slug', 'foo')->get());
    }

    public function testRecreateSlugs()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-update-vehicle-slug',
            'value' => 'boolean',
            'type' => true,

        ]);

        Vehicle::factory(5)->create([
            'title' => 'foo',
        ]);

        // Update vehicle slugs without triggering observer functions.
        // This should force a scenario with duplicate slugs.
        Vehicle::query()->get()->each(function ($vehicle) {
            $vehicle->slug = 'foo';
            $vehicle->saveQuietly();
        });

        // assert that we have duplicate slugs
        $this->assertCount(5, Vehicle::query()->where('slug', 'foo')->get());

        (new RecreateVehicleSlugs())->handle(App::make(VehicleRepository::class));

        // assert that we have 5 vehicles and that original slug is not duplicated
        $this->assertCount(5, Vehicle::query()->get());
        $this->assertCount(1, Vehicle::query()->where('slug', 'foo')->get());
    }

    public function testVehicleReportFunctions()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'distance measurement',
            'config_key' => 'automotive-distance_measurement',
            'value' => 'mi',
            'type' => 'string',
        ]);

        $vehicle = Vehicle::factory()->create([
            'created_at' => '2020-11-23 01:23:45',
            'first_registration_date' => '2019-01-02',
            'engine_size_cc' => 1234,
        ]);

        // valid enquiries for this vehicle
        Enquiry::factory(3)->create([
            'reason_type' => 'vehicle',
            'reason_id' => $vehicle->id,
            'created_at' => Carbon::now()->subHours(10),
        ]);

        // valid enquiries for different vehicle
        Enquiry::factory(4)->create([
            'reason_type' => 'vehicle',
            'reason_id' => $vehicle->id + 1,
            'created_at' => Carbon::now()->subHours(10),
        ]);

        // invalid enquiries for this vehicle
        Enquiry::factory(4)->create([
            'reason_type' => 'vehicle',
            'reason_id' => $vehicle->id,
            'created_at' => Carbon::now()->subDays(2),
        ]);

        ResourceView::query()->create([
            'viewable_type' => 'vehicle',
            'viewable_id' => $vehicle->id,
            'hits' => 5,
            'date' => '2020-01-01',
        ]);

        ResourceView::query()->create([
            'viewable_type' => 'vehicle',
            'viewable_id' => $vehicle->id,
            'hits' => 3,
            'date' => '2020-02-02',
        ]);

        ResourceView::query()->create([
            'viewable_type' => 'vehicle',
            'viewable_id' => $vehicle->id + 1,
            'hits' => 7,
            'date' => '2020-02-02',
        ]);

        $this->assertEquals('2020-11-23', $vehicle->dateCreated);
        $this->assertEquals(1.3, $vehicle->engineSizeLitres);
        $this->assertEquals('mi', $vehicle->odometerUnits);
        $this->assertEquals(3, $vehicle->videoCount);
        $this->assertEquals(2019, $vehicle->registrationYear);
        $this->assertEquals(3, $vehicle->last24HoursEnquiries()->count());
        $this->assertTrue($vehicle->hasVideo);
        $this->assertEquals(8, $vehicle->impressions);
    }

    public function testRepositorySlugType()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'automotive-vehicles-url_building_format',
            'type' => 'string',
            'value' => 'title',
        ]);

        $vehicle = Vehicle::factory()->make([
            'title' => 'foo',
            'uuid' => 'bar/baz',
        ]);

        // assert that we get the expected slug based on config setting
        $this->assertEquals('foo', (App::make(VehicleRepository::class)->buildSlug($vehicle)));

        // assert that we get expected sanitised slug based on requested slug type
        $this->assertEquals('barbaz', (App::make(VehicleRepository::class)->buildSlug($vehicle, 'uuid')));
    }
}
