<?php

namespace Tests\Tenant;

use App\Facades\Feature;
use Mtc\MercuryDataModels\CarConfiguratorColour;
use Mtc\MercuryDataModels\CarConfiguratorCustomSection;
use Mtc\MercuryDataModels\CarConfiguratorEngine;
use Mtc\MercuryDataModels\CarConfiguratorInterior;
use Mtc\MercuryDataModels\CarConfiguratorModel;
use Mtc\MercuryDataModels\CarConfiguratorRestriction;
use Mtc\MercuryDataModels\CarConfiguratorSection;
use Mtc\MercuryDataModels\CarConfiguratorTrim;
use Mtc\MercuryDataModels\CarConfiguratorWheel;
use Mtc\MercuryDataModels\CustomerCarConfiguration;
use Tests\TenantTestCase;

class CarConfiguratorTest extends TenantTestCase
{
    public function testShow()
    {
        Feature::setEnabled(tenant(), ['car-configurator']);
        $model = CarConfiguratorModel::factory()->create(['active' => true]);
        CarConfiguratorTrim::factory(2)->create(['model_id' => $model->id]);
        CarConfiguratorEngine::factory(3)->create(['model_id' => $model->id]);
        CarConfiguratorColour::factory(4)->create(['model_id' => $model->id]);
        CarConfiguratorWheel::factory(5)->create(['model_id' => $model->id]);
        CarConfiguratorInterior::factory(1)->create(['model_id' => $model->id]);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Trims']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Engines']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Colours']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Wheels']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Interiors']);
        $response = $this->postJson(route('configurator.show', $model->slug));
        $response->assertStatus(200);
        $this->assertEquals($model->slug, $response->json('data.slug'));
        $this->assertEquals($model->name, $response->json('data.name'));
        $this->assertArrayHasKey('media_uses', $response->json('data'));
        $this->assertArrayHasKey('interior', $response->json('data.media_uses'));
        $this->assertArrayHasKey('exterior', $response->json('data.media_uses'));
        $this->assertArrayHasKey('sections', $response->json('data'));
        $this->assertArrayHasKey('colours', $response->json('data.sections'));
        $this->assertArrayHasKey('trims', $response->json('data.sections'));
        $this->assertArrayHasKey('engines', $response->json('data.sections'));
        $this->assertArrayHasKey('wheels', $response->json('data.sections'));
        $this->assertArrayHasKey('interiors', $response->json('data.sections'));
        $this->assertCount(2, $response->json('data.sections.trims.items'));
        $this->assertCount(3, $response->json('data.sections.engines.items'));
        $this->assertCount(4, $response->json('data.sections.colours.items'));
        $this->assertCount(5, $response->json('data.sections.wheels.items'));
        $this->assertCount(1, $response->json('data.sections.interiors.items'));
    }

    public function testRestrictionsOnShow()
    {
        Feature::setEnabled(tenant(), ['car-configurator']);
        $model = CarConfiguratorModel::factory()->create(['active' => true]);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Trims']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Engines']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Colours']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Wheels']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Interiors']);

        $trim1 = CarConfiguratorTrim::factory()->create(['model_id' => $model->id]);
        $trim2 = CarConfiguratorTrim::factory()->create(['model_id' => $model->id]);
        CarConfiguratorEngine::factory(3)->create(['model_id' => $model->id]);
        $colour = CarConfiguratorColour::factory()->create(['model_id' => $model->id]);
        CarConfiguratorColour::factory(4)->create(['model_id' => $model->id]);
        $wheel = CarConfiguratorWheel::factory()->create(['model_id' => $model->id]);
        CarConfiguratorWheel::factory(2)->create(['model_id' => $model->id]);
        CarConfiguratorInterior::factory(1)->create(['model_id' => $model->id]);
        CarConfiguratorRestriction::query()->create([
            'model_id' => $model->id,
            'functionality_id' => $wheel->id,
            'functionality_type' => $wheel->getMorphClass(),
            'restriction_id' => $trim1->id,
            'restriction_type' => 'trims',
            'condition' => 'is_allowed',
        ]);
        CarConfiguratorRestriction::query()->create([
            'model_id' => $model->id,
            'functionality_id' => $colour->id,
            'functionality_type' => $colour->getMorphClass(),
            'restriction_id' => $trim1->id,
            'restriction_type' => 'trims',
            'condition' => 'not_allowed',
        ]);
        $response = $this->postJson(route('configurator.show', $model->slug), [
            'sections' => [
                'trims' => [
                    'selected' => $trim1->id,
                ],
            ]
        ]);
        $response->assertStatus(200);
        $this->assertCount(3, $response->json('data.sections.wheels.items'));
        $response = $this->postJson(route('configurator.show', $model->slug), [
            'sections' => [
                'trims' => [
                    'selected' => $trim2->id,
                ],
            ]
        ]);
        $response->assertStatus(200);
        $this->assertCount(2, $response->json('data.sections.wheels.items'));
        $response = $this->postJson(route('configurator.show', $model->slug), [
            'sections' => [
                'trims' => [
                    'selected' => $trim1->id,
                ],
            ]
        ]);
        $response->assertStatus(200);
        $this->assertCount(4, $response->json('data.sections.colours.items'));
        $response = $this->postJson(route('configurator.show', $model->slug), [
            'sections' => [
                'trims' => [
                    'selected' => $trim2->id,
                ],
            ]
        ]);
        $response->assertStatus(200);
        $this->assertCount(5, $response->json('data.sections.colours.items'));

        $response = $this->postJson(route('configurator.show', $model->slug), [
            'sections' => [
                'trims' => [
                    'selected' => $trim1->id,
                ],
                'colours' => [
                    'selected' => $colour->id,
                ]
            ]
        ]);
        $response->assertStatus(422);
    }

    public function testPriceRuleWithUnresolvableRestrictionTypeDoesNotError()
    {
        Feature::setEnabled(tenant(), ['car-configurator']);
        $model = CarConfiguratorModel::factory()->create(['active' => true]);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Trims']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Wheels']);

        $trim = CarConfiguratorTrim::factory()->create(['model_id' => $model->id]);
        $wheel = CarConfiguratorWheel::factory()->create([
            'model_id' => $model->id,
            'price' => 750,
            'data' => [
                'prices' => [
                    ['restriction_type' => '', 'restriction_id' => $trim->id, 'price' => 500],
                ],
            ],
        ]);

        $response = $this->postJson(route('configurator.show', $model->slug), [
            'sections' => [
                'trims' => [
                    'selected' => $trim->id,
                ],
            ],
        ]);

        $response->assertStatus(200);
        $wheels = collect($response->json('data.sections.wheels.items'));
        $this->assertEquals(750, $wheels->firstWhere('id', $wheel->id)['price']);
    }

    public function testCustomSections()
    {
        Feature::setEnabled(tenant(), ['car-configurator']);
        $model = CarConfiguratorModel::factory()->create(['active' => true]);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Trims']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Engines']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Colours']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Wheels']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Interiors']);
        CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Interiors']);
        $section = CarConfiguratorSection::factory()->create([
            'model_id' => $model->id,
            'name' => 'Seats',
            'custom' => true
        ]);

        CarConfiguratorTrim::factory()->create(['model_id' => $model->id]);
        CarConfiguratorEngine::factory()->create(['model_id' => $model->id]);
        CarConfiguratorColour::factory()->create(['model_id' => $model->id]);
        CarConfiguratorColour::factory(4)->create(['model_id' => $model->id]);
        CarConfiguratorWheel::factory()->create(['model_id' => $model->id]);
        CarConfiguratorWheel::factory(2)->create(['model_id' => $model->id]);
        CarConfiguratorInterior::factory()->create(['model_id' => $model->id]);
        CarConfiguratorCustomSection::factory(3)->create([
            'section_id' => $section->id,
            'model_id' => $model->id
        ]);
        $response = $this->postJson(route('configurator.show', $model->slug));
        $response->assertStatus(200);
        $this->assertArrayHasKey('seats', $response->json('data.sections'));
        $this->assertCount(3, $response->json('data.sections.seats.items'));
    }

    public function testStore()
    {
        Feature::setEnabled(tenant(), ['car-configurator']);
        $model = CarConfiguratorModel::factory()->create(['active' => true]);
        $s1 = CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Trims']);
        $s2 = CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Engines']);
        $s3 = CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Colours']);
        $s4 = CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Wheels']);
        $s5 = CarConfiguratorSection::factory()->create(['model_id' => $model->id, 'name' => 'Interiors']);

        $trim = CarConfiguratorTrim::factory()->create(['model_id' => $model->id]);
        $engine = CarConfiguratorEngine::factory()->create(['model_id' => $model->id]);
        $colour = CarConfiguratorColour::factory()->create(['model_id' => $model->id]);
        CarConfiguratorColour::factory(4)->create(['model_id' => $model->id]);
        $wheel = CarConfiguratorWheel::factory()->create(['model_id' => $model->id]);
        CarConfiguratorWheel::factory(2)->create(['model_id' => $model->id]);
        $interior = CarConfiguratorInterior::factory()->create(['model_id' => $model->id]);

        $response = $this->putJson(route('configurator.store', $model->slug), [
            'sections' => [
                'trims' => [
                     'id' => $s1->id,
                    'selected' => $trim->id,
                ],
                'engines' => [
                    'id' => $s2->id,
                    'selected' => $engine->id,
                ],
                'colours' => [
                    'id' => $s3->id,
                    'selected' => $colour->id,
                ],
                'wheels' => [
                    'id' => $s4->id,
                    'selected' => $wheel->id,
                ],
            ]
        ]);
        // missing section
        $response->assertStatus(422);

        $response = $this->putJson(route('configurator.store', $model->slug), [
            'sections' => [
                'trims' => [
                    'id' => $s1->id,
                    'selected' => $trim->id,
                ],
                'engines' => [
                    'id' => $s2->id,
                    'selected' => $engine->id,
                ],
                'colours' => [
                    'id' => $s3->id,
                    'selected' => $colour->id,
                ],
                'wheels' => [
                    'id' => $s4->id,
                    'selected' => $wheel->id,
                ],
                'interiors' => [
                    'id' => $s5->id,
                    'selected' => $interior->id,
                ],
            ]
        ]);
        $response->assertStatus(400);
        $response = $this->putJson(route('configurator.store', $model->slug), [
            'sections' => [
                'trims' => [
                    'id' => $s1->id,
                    'selected' => $trim->id,
                    'items' => [
                        $trim->only(['id', 'name']),
                    ]
                ],
                'engines' => [
                    'id' => $s2->id,
                    'selected' => $engine->id,
                    'items' => [
                        $engine->only(['id', 'name']),
                    ]
                ],
                'colours' => [
                    'id' => $s3->id,
                    'selected' => $colour->id,
                    'items' => [
                        $colour->only(['id', 'name']),
                    ]
                ],
                'wheels' => [
                    'id' => $s4->id,
                    'selected' => $wheel->id,
                    'items' => [
                        $wheel->only(['id', 'name']),
                    ]
                ],
                'interiors' => [
                    'id' => $s5->id,
                    'selected' => $interior->id,
                    'items' => [
                        $interior->only(['id', 'name']),
                    ]
                ],
            ]
        ]);
        $response->assertStatus(201);
        $this->assertArrayHasKey('message', $response->json());
        $this->assertArrayHasKey('uuid', $response->json());
        $this->assertArrayHasKey('id', $response->json());
    }

    public function testView()
    {
        Feature::setEnabled(tenant(), ['car-configurator']);
        $configuration = CustomerCarConfiguration::factory()->create();
        $response = $this->getJson(route('configurator.view', $configuration->uuid));
        $response->assertStatus(404);

        $model = CarConfiguratorModel::factory()->create(['active' => true]);
        $configuration = CustomerCarConfiguration::factory()->create(['model_id' => $model->id]);
        $response = $this->getJson(route('configurator.view', $configuration->uuid));
        $response->assertStatus(200);

        $response->assertStatus(200);
        $this->assertArrayHasKey('customer', $response->json());
        $this->assertArrayHasKey('configurator', $response->json());
    }
}
