<?php

namespace Tests\Feature;

use App\Facades\Settings;
use App\Imports\DealerInternetImport;
use App\Jobs\ImportImagesFromUrlList;
use App\Modules\Stock\DealerInternet;
use App\TaxonomyMap;
use DOMDocument;
use DOMXPath;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Http;
use Mtc\MercuryDataModels\Franchise;
use Mtc\MercuryDataModels\TransmissionType;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleOffer;
use Mtc\MercuryDataModels\VehicleOfferFinance;
use Tests\TestCase;
use Tests\UserForTenant;

/**
 * Testing for Pye Motors / Dealer Internet scraping
 */
class DealerInternetScrapeTest extends TestCase
{
    use RefreshDatabase;
    use UserForTenant;

    protected $tenancy = true;

    public function testGetModelLinks()
    {
        $username = 'mtctest';

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Enabled',
            'config_key' => 'stock-dealer-internet-enabled',
            'type' => 'boolean',
            'value' => true,
            'order' => 1,
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Username',
            'config_key' => 'stock-dealer-internet-username',
            'type' => 'string',
            'value' => $username,
            'validation_rules' => [
                "required_if:values.stock-dealer-internet-enabled,true"
            ]
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Make to import',
            'config_key' => 'stock-dealer-internet-make-to-import',
            'type' => 'string',
            'value' => 'Ford',
        ]);

        Http::fake([
            'https://www.dealerinternet.co.uk/web/' . $username . '/car' =>
            Http::response(
                file_get_contents(dirname(__DIR__) . '/data/dealer-internet-car-page.html'),
                200
            ),
            '*' => Http::response(null, 400),
        ]);

        $urls = (new DealerInternetImport())->getModelStockUrls();

        $this->assertCount(12, $urls);
        $this->assertArrayHasKey('Puma Gen-E', $urls);
        $this->assertArrayHasKey('Mustang', $urls);
        $this->assertEquals('/car/puma-gen-e/', $urls['Puma Gen-E']);
        $this->assertEquals('/car/new-mustang/', $urls['Mustang']);
    }

    public function testGetModelStock()
    {
        $username = 'mtctest';

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Enabled',
            'config_key' => 'stock-dealer-internet-enabled',
            'type' => 'boolean',
            'value' => true,
            'order' => 1,
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Username',
            'config_key' => 'stock-dealer-internet-username',
            'type' => 'string',
            'value' => $username,
            'validation_rules' => [
                "required_if:values.stock-dealer-internet-enabled,true"
            ]
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Make to import',
            'config_key' => 'stock-dealer-internet-make-to-import',
            'type' => 'string',
            'value' => 'Ford',
        ]);

        $model_path = '/car/focus/';

        Http::fake([
            'https://www.dealerinternet.co.uk/web/' . $username . $model_path . 'stock/all/' =>
                Http::response(
                    file_get_contents(dirname(__DIR__) . '/data/dealer-internet-car-model-stock.html'),
                    200
                ),
            '*' => Http::response(null, 400),
        ]);

        $stock = (new DealerInternetImport())->getModelStock($model_path);

        $this->assertCount(87, $stock);
    }

    public function testImportStock()
    {
        Bus::fake();

        $make_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-make',
            'taxonomy_id' => 55,
            'term' => 'Ford',
            'provider' => 'foo',
        ]);

        $model_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-model',
            'taxonomy_id' => 99,
            'parent_id' => $make_taxonomy->taxonomy_id,
            'term' => 'Focus',
            'provider' => 'foo',
        ]);

        $transmission_manual = TransmissionType::factory()->create([
            'name' => 'Manual',
        ]);

        $transmission_auto = TransmissionType::factory()->create([
            'name' => 'Automatic',
        ]);

        TaxonomyMap::query()->create([
            'taxonomy_type' => 'transmission',
            'term' => 'manual',
            'provider' => 'dealer-internet-import',
            'taxonomy_id' => $transmission_manual->id,
        ]);

        TaxonomyMap::query()->create([
            'taxonomy_type' => 'transmission',
            'term' => 'automatic',
            'provider' => 'dealer-internet-import',
            'taxonomy_id' => $transmission_auto->id,
        ]);

        $this->setupForImport($make_taxonomy->taxonomy_id, $model_taxonomy->taxonomy_id);

        (new DealerInternet())->runScheduledImport();

        // assert that we saved the expected vehicles
        $this->assertCount(87, VehicleOffer::all());
        $this->assertCount(87, VehicleOfferFinance::all());

        $example = VehicleOffer::query()
            ->where('key_features', 'LIKE', '%design%')
            ->where('key_features', 'LIKE', '%winter%')
            ->first();

        $this->assertEquals('H0363', $example->uuid);
        $this->assertEquals('ford-focus-10l-ecoboost-155ps-mhev-10', $example->slug);
        $this->assertEquals('dealer-internet-import', $example->stock_provider);
        $this->assertEquals('Ford Focus 1.0L EcoBoost 155PS mHEV', $example->name);
        $this->assertEquals('1.0L EcoBoost 155PS mHEV', $example->derivative);
        $this->assertEquals('ST-Line', $example->trim);
        $this->assertEquals('Chrome Blue', $example->colour);
        $this->assertEquals(31807.52, $example->price);
        $this->assertEquals(33840, $example->full_price);
        $this->assertTrue(in_array('ST-Line Design Pack', $example->key_features));
        $this->assertTrue(in_array('Winter Pack', $example->key_features));
        $this->assertEquals($make_taxonomy->taxonomy_id, $example->make_id);
        $this->assertEquals($model_taxonomy->taxonomy_id, $example->model_id);
        $this->assertEquals('Ford', $example->make->name);
        $this->assertEquals('Focus', $example->model->name);
        $this->assertEquals('Automatic', $example->transmission?->name);
        $this->assertEquals('new', $example->type);
        $this->assertNull($example->franchise_id);

        $finance = $example->finance->first();

        $this->assertEquals('dealer-internet-import', $finance->provider);
        $this->assertEquals(6000, $finance->annual_mileage);
        $this->assertEquals(31807.52, $finance->full_price);
        $this->assertEquals(11132.63, $finance->customer_deposit);
        $this->assertEquals(1000, $finance->dealer_deposit_contribution);
        $this->assertEquals(12132.63, $finance->deposit);
        $this->assertEquals(31807.52, $finance->total_amount);
        $this->assertEquals(20674.89, $finance->total_credit_amount);
        $this->assertEquals(0, $finance->apr);
        $this->assertEquals(0, $finance->interest_rate);
        $this->assertEquals(38, $finance->term);
        $this->assertEquals(38, $finance->number_of_payments);
        $this->assertEquals(183.92, $finance->monthly_price);
        $this->assertEquals('PCP', $finance->finance_type);

        Bus::assertDispatched(ImportImagesFromUrlList::class);
    }

    public function testImportStockWithFranchise()
    {
        Bus::fake();

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Make to import',
            'config_key' => 'stock-dealer-internet-make-to-import',
            'type' => 'string',
            'value' => 'Ford',
        ]);

        $franchise = Franchise::factory()->create([
            'slug' => 'ford',
        ]);

        $make_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-make',
            'taxonomy_id' => 55,
            'term' => 'Ford',
            'provider' => 'foo',
        ]);

        $model_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-model',
            'taxonomy_id' => 99,
            'parent_id' => $make_taxonomy->taxonomy_id,
            'term' => 'Focus',
            'provider' => 'foo',
        ]);

        $transmission_manual = TransmissionType::factory()->create([
            'name' => 'Manual',
        ]);

        $transmission_auto = TransmissionType::factory()->create([
            'name' => 'Automatic',
        ]);

        TaxonomyMap::query()->create([
            'taxonomy_type' => 'transmission',
            'term' => 'manual',
            'provider' => 'dealer-internet-import',
            'taxonomy_id' => $transmission_manual->id,
        ]);

        TaxonomyMap::query()->create([
            'taxonomy_type' => 'transmission',
            'term' => 'automatic',
            'provider' => 'dealer-internet-import',
            'taxonomy_id' => $transmission_auto->id,
        ]);

        $this->setupForImport($make_taxonomy->taxonomy_id, $model_taxonomy->taxonomy_id);

        (new DealerInternet())->runScheduledImport();

        // assert that we saved the expected vehicles
        $this->assertCount(87, VehicleOffer::all());
        $this->assertCount(87, VehicleOfferFinance::all());

        $example = VehicleOffer::query()
            ->where('key_features', 'LIKE', '%design%')
            ->where('key_features', 'LIKE', '%winter%')
            ->first();

        $this->assertEquals('H0363', $example->uuid);
        $this->assertEquals('ford-focus-10l-ecoboost-155ps-mhev-10', $example->slug);
        $this->assertEquals('dealer-internet-import', $example->stock_provider);
        $this->assertEquals('Ford Focus 1.0L EcoBoost 155PS mHEV', $example->name);
        $this->assertEquals('1.0L EcoBoost 155PS mHEV', $example->derivative);
        $this->assertEquals('ST-Line', $example->trim);
        $this->assertEquals('Chrome Blue', $example->colour);
        $this->assertEquals(31807.52, $example->price);
        $this->assertEquals(33840, $example->full_price);
        $this->assertTrue(in_array('ST-Line Design Pack', $example->key_features));
        $this->assertTrue(in_array('Winter Pack', $example->key_features));
        $this->assertEquals($make_taxonomy->taxonomy_id, $example->make_id);
        $this->assertEquals($model_taxonomy->taxonomy_id, $example->model_id);
        $this->assertEquals('Ford', $example->make->name);
        $this->assertEquals('Focus', $example->model->name);
        $this->assertEquals('Automatic', $example->transmission?->name);
        $this->assertEquals('new', $example->type);
        $this->assertEquals($franchise->id, $example->franchise_id);

        $finance = $example->finance->first();

        $this->assertEquals('dealer-internet-import', $finance->provider);
        $this->assertEquals(6000, $finance->annual_mileage);
        $this->assertEquals(31807.52, $finance->full_price);
        $this->assertEquals(11132.63, $finance->customer_deposit);
        $this->assertEquals(1000, $finance->dealer_deposit_contribution);
        $this->assertEquals(12132.63, $finance->deposit);
        $this->assertEquals(31807.52, $finance->total_amount);
        $this->assertEquals(20674.89, $finance->total_credit_amount);
        $this->assertEquals(0, $finance->apr);
        $this->assertEquals(0, $finance->interest_rate);
        $this->assertEquals(38, $finance->term);
        $this->assertEquals(38, $finance->number_of_payments);
        $this->assertEquals(183.92, $finance->monthly_price);
        $this->assertEquals('PCP', $finance->finance_type);

        Bus::assertDispatched(ImportImagesFromUrlList::class);
    }

    public function testDeleteNoInitialOffers()
    {
        $make_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-make',
            'taxonomy_id' => 55,
            'term' => 'Ford',
            'provider' => 'foo',
        ]);

        $model_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-model',
            'taxonomy_id' => 99,
            'parent_id' => $make_taxonomy->taxonomy_id,
            'term' => 'Focus',
            'provider' => 'foo',
        ]);

        $this->setupForImport($make_taxonomy->taxonomy_id, $model_taxonomy->taxonomy_id);

        $this->assertCount(0, VehicleOffer::all());

        (new DealerInternet())->runScheduledImport();

        $this->assertCount(87, VehicleOffer::all());
    }

    public function testDeleteOldOffers()
    {
        $make_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-make',
            'taxonomy_id' => 55,
            'term' => 'Ford',
            'provider' => 'foo',
        ]);

        $model_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-model',
            'taxonomy_id' => 99,
            'parent_id' => $make_taxonomy->taxonomy_id,
            'term' => 'Focus',
            'provider' => 'foo',
        ]);

        $this->setupForImport($make_taxonomy->taxonomy_id, $model_taxonomy->taxonomy_id);

        $offer = VehicleOffer::factory()->create([
            'uuid' => 'mtc-test'
        ]);

        $this->assertCount(1, VehicleOffer::query()->where('id', $offer->id)->get());

        (new DealerInternet())->runScheduledImport();

        $this->assertCount(88, VehicleOffer::all());
        $this->assertCount(1, VehicleOffer::query()->where('id', $offer->id)->get());
        // 87 import jobs for images
        Queue::assertCount(87);
    }

    public function testDeleteOldMissingData()
    {
        $make_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-make',
            'taxonomy_id' => 55,
            'term' => 'Ford',
            'provider' => 'foo',
        ]);

        $model_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-model',
            'taxonomy_id' => 99,
            'parent_id' => $make_taxonomy->taxonomy_id,
            'term' => 'Focus',
            'provider' => 'foo',
        ]);

        $username = 'mtctest';

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Enabled',
            'config_key' => 'stock-dealer-internet-enabled',
            'type' => 'boolean',
            'value' => true,
            'order' => 1,
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Username',
            'config_key' => 'stock-dealer-internet-username',
            'type' => 'string',
            'value' => $username,
            'validation_rules' => [
                "required_if:values.stock-dealer-internet-enabled,true"
            ]
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Make to import',
            'config_key' => 'stock-dealer-internet-make-to-import',
            'type' => 'string',
            'value' => 'Ford',
        ]);

        VehicleMake::factory()->create([
            'id' => $make_taxonomy->taxonomy_id,
            'name' => 'Ford',
        ]);

        VehicleModel::factory()->create([
            'id' => $model_taxonomy->taxonomy_id,
            'name' => 'Focus',
        ]);

        $path = '/car/focus/stock/all/';

        Http::fake([
            'https://www.dealerinternet.co.uk/web/' . $username . '/car' =>
                Http::response(
                    '',
                    200
                ),
            'https://www.dealerinternet.co.uk/web/' . $username . $path =>
                Http::response(
                    '',
                    200
                ),
            '*' => Http::response(null, 400),
        ]);

        VehicleOffer::factory(5)->create();

        $this->assertCount(5, VehicleOffer::all());

        (new DealerInternet())->runScheduledImport();

        // There were no vehicles to import.
        // Assert that we didn't delete any existing offers.
        $this->assertCount(5, VehicleOffer::all());
    }

    public function testPublishStatusTrue()
    {
        Bus::fake();

        $make_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-make',
            'taxonomy_id' => 55,
            'term' => 'Ford',
            'provider' => 'foo',
        ]);

        $model_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-model',
            'taxonomy_id' => 99,
            'parent_id' => $make_taxonomy->taxonomy_id,
            'term' => 'Focus',
            'provider' => 'foo',
        ]);

        $this->setupForImport($make_taxonomy->taxonomy_id, $model_taxonomy->taxonomy_id);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'foo',
            'config_key' => 'stock-dealer-internet-default-to-published',
            'type' => 'boolean',
            'value' => true,
        ]);

        VehicleOffer::factory()->create([
            'uuid' => 'H0363',
            'published' => false,
        ]);

        (new DealerInternet())->runScheduledImport();

        // assert that we saved the expected vehicles
        $this->assertCount(87, VehicleOffer::all());

        // assert existing offers do not get status changed
        $this->assertCount(86, VehicleOffer::query()->where('published', true)->get());
        $this->assertNotNull(VehicleOffer::query()->where('published', false)->where('uuid', 'H0363')->first());
    }

    public function testPublishStatusFalse()
    {
        Bus::fake();

        $make_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-make',
            'taxonomy_id' => 55,
            'term' => 'Ford',
            'provider' => 'foo',
        ]);

        $model_taxonomy = TaxonomyMap::query()->create([
            'taxonomy_type' => 'master-model',
            'taxonomy_id' => 99,
            'parent_id' => $make_taxonomy->taxonomy_id,
            'term' => 'Focus',
            'provider' => 'foo',
        ]);

        $this->setupForImport($make_taxonomy->taxonomy_id, $model_taxonomy->taxonomy_id);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'foo',
            'config_key' => 'stock-dealer-internet-default-to-published',
            'type' => 'boolean',
            'value' => false,
        ]);

        VehicleOffer::factory()->create([
            'uuid' => 'H0363',
            'published' => true,
        ]);

        (new DealerInternet())->runScheduledImport();

        // assert that we saved the expected vehicles
        $this->assertCount(87, VehicleOffer::all());

        // assert existing offers do not get status changed
        $this->assertCount(86, VehicleOffer::query()->where('published', false)->get());
        $this->assertNotNull(VehicleOffer::query()->where('published', true)->where('uuid', 'H0363')->first());
    }

    private function setupForImport($make_id, $model_id)
    {
        Queue::fake([ImportImagesFromUrlList::class]);
        $username = 'mtctest';

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Enabled',
            'config_key' => 'stock-dealer-internet-enabled',
            'type' => 'boolean',
            'value' => true,
            'order' => 1,
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Username',
            'config_key' => 'stock-dealer-internet-username',
            'type' => 'string',
            'value' => $username,
            'validation_rules' => [
                "required_if:values.stock-dealer-internet-enabled,true"
            ]
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'foo',
            'group' => 'Dealer Internet',
            'name' => 'Make to import',
            'config_key' => 'stock-dealer-internet-make-to-import',
            'type' => 'string',
            'value' => 'Ford',
        ]);

        VehicleMake::factory()->create([
            'id' => $make_id,
            'name' => 'Ford',
        ]);

        VehicleModel::factory()->create([
            'id' => $model_id,
            'name' => 'Focus',
        ]);

        $path = '/car/focus/stock/all/';

        Http::fake([
            'https://www.dealerinternet.co.uk/web/' . $username . '/car' =>
                Http::response(
                    file_get_contents(dirname(__DIR__) . '/data/dealer-internet-car-page.html'),
                    200
                ),
            'https://www.dealerinternet.co.uk/web/' . $username . $path =>
                Http::response(
                    file_get_contents(dirname(__DIR__) . '/data/dealer-internet-car-model-stock.html'),
                    200
                ),
            '*' => Http::response(null, 400),
        ]);
    }
}
