<?php

namespace Tests\Feature;

use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleTrim;
use Tests\DatabaseTestCase;
use Tests\UserForTenant;

class VehicleTrimAttributeTest extends DatabaseTestCase
{
    use UserForTenant;

    public function testIndexAttributesForVehicleTrim()
    {
        VehicleAttribute::factory(3)->create(['model' => 'vehicle-trim']);
        VehicleAttribute::factory(2)->create(['model' => 'vehicle']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.attributes.index', 'vehicle-trim'));

        $response->assertStatus(200);
        $this->assertIsArray($response->json('data'));
        $this->assertCount(3, $response->json('data'));
    }

    public function testStoreAttributeForVehicleTrim()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.attributes.store', 'vehicle-trim'), [
                'name' => 'Trim Colour Option',
                'type' => 'text',
            ]);

        $response->assertStatus(201);
        $this->assertEquals('Trim Colour Option', $response->json('attribute.name'));
        $this->assertEquals('text', $response->json('attribute.type'));
        $this->assertTrue(
            VehicleAttribute::query()
                ->where('name', 'Trim Colour Option')
                ->where('model', 'vehicle-trim')
                ->exists()
        );
    }

    public function testShowAttributeForVehicleTrim()
    {
        $attribute = VehicleAttribute::factory()->create([
            'model' => 'vehicle-trim',
            'name' => 'Trim Weight',
            'type' => 'number',
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.attributes.show', ['vehicle-trim', $attribute]));

        $response->assertStatus(200);
        $this->assertEquals('Trim Weight', $response->json('attribute.name'));
        $this->assertEquals('number', $response->json('attribute.type'));
    }

    public function testUpdateAttributeForVehicleTrim()
    {
        $attribute = VehicleAttribute::factory()->create(['model' => 'vehicle-trim']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.attributes.update', ['vehicle-trim', $attribute]), [
                'name' => 'Updated Trim Attribute',
                'type' => 'number',
                'count' => 2,
            ]);

        $response->assertStatus(200);
        $attribute->refresh();
        $this->assertEquals('Updated Trim Attribute', $attribute->name);
        $this->assertEquals('number', $attribute->type);
        $this->assertEquals(2, $attribute->count);
    }

    public function testDestroyAttributeForVehicleTrim()
    {
        $attribute = VehicleAttribute::factory()->create(['model' => 'vehicle-trim']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('tenant.attributes.destroy', ['vehicle-trim', $attribute]));

        $response->assertStatus(200);
        $this->assertFalse(VehicleAttribute::query()->where('id', $attribute->id)->exists());
    }

    public function testUpdateTrimSavesAttributeValues()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $newCar = NewCar::factory()->create();
        $trim = VehicleTrim::query()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'Test Trim',
        ]);

        $attribute = VehicleAttribute::factory()->create([
            'model' => 'vehicle-trim',
            'name' => 'Custom Option',
            'slug' => 'custom_option',
            'type' => 'text',
            'count' => 1,
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.vehicle-trims.update', $trim), [
                'make_id' => $make->id,
                'new_car_id' => $newCar->id,
                'name' => 'Test Trim',
                'extra' => [
                    [
                        'id' => $attribute->id,
                        'slug' => $attribute->slug,
                        'type' => $attribute->type,
                        'value' => [
                            ['id' => null, 'value' => 'Metallic Blue'],
                        ],
                    ],
                ],
            ]);

        $response->assertStatus(200);

        $savedValue = VehicleAttributeValue::query()
            ->where('owner_id', $trim->id)
            ->where('owner_type', 'vehicle-trim')
            ->where('attribute_id', $attribute->id)
            ->first();

        $this->assertNotNull($savedValue);
        $this->assertEquals('Metallic Blue', $savedValue->value_text);
    }

    public function testShowTrimReturnsExtraAttributes()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $trim = VehicleTrim::query()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'Show Trim',
        ]);

        $attribute = VehicleAttribute::factory()->create([
            'model' => 'vehicle-trim',
            'name' => 'Trim Feature',
            'slug' => 'trim_feature',
            'type' => 'text',
            'count' => 1,
        ]);

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $trim->id,
            'owner_type' => 'vehicle-trim',
            'slug' => 'trim_feature',
            'type' => 'text',
            'value_text' => 'Heated Seats',
            'index' => 0,
            'order' => 0,
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.vehicle-trims.show', $trim));

        $response->assertStatus(200);
        $this->assertArrayHasKey('extra', $response->json());

        $extra = collect($response->json('extra'));
        $trimFeature = $extra->where('slug', 'trim_feature')->first();
        $this->assertNotNull($trimFeature);
        $this->assertEquals('Trim Feature', $trimFeature['name']);
        $this->assertEquals('Heated Seats', $trimFeature['value'][0]['value']);
    }

    public function testUpdateTrimRemovesDeletedAttributeValues()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $newCar = NewCar::factory()->create();
        $trim = VehicleTrim::query()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'Delete Test Trim',
        ]);

        $attribute = VehicleAttribute::factory()->create([
            'model' => 'vehicle-trim',
            'name' => 'Removable Option',
            'slug' => 'removable_option',
            'type' => 'text',
            'count' => 1,
        ]);

        $existingValue = VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $trim->id,
            'owner_type' => 'vehicle-trim',
            'slug' => 'removable_option',
            'type' => 'text',
            'value_text' => 'Old Value',
            'index' => 0,
            'order' => 0,
        ]);

        // Send update with empty value to remove the attribute value
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.vehicle-trims.update', $trim), [
                'make_id' => $make->id,
                'new_car_id' => $newCar->id,
                'name' => 'Delete Test Trim',
                'extra' => [
                    [
                        'id' => $attribute->id,
                        'slug' => $attribute->slug,
                        'type' => $attribute->type,
                        'value' => [
                            ['id' => $existingValue->id, 'value' => ''],
                        ],
                    ],
                ],
            ]);

        $response->assertStatus(200);
        $this->assertFalse(
            VehicleAttributeValue::query()->where('id', $existingValue->id)->exists()
        );
    }

    public function testCopyTrimDuplicatesAttributeValues()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $trim = VehicleTrim::query()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'Copy Source Trim',
        ]);

        $attribute = VehicleAttribute::factory()->create([
            'model' => 'vehicle-trim',
            'name' => 'Copyable Feature',
            'slug' => 'copyable_feature',
            'type' => 'text',
            'count' => 1,
        ]);

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $trim->id,
            'owner_type' => 'vehicle-trim',
            'slug' => 'copyable_feature',
            'type' => 'text',
            'value_text' => 'Premium Package',
            'index' => 0,
            'order' => 0,
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.vehicle-trims.copy', $trim));

        $response->assertStatus(201);

        $copyId = $response->json('id');
        $this->assertNotEquals($trim->id, $copyId);

        // Verify attribute values were duplicated to the copy
        $copiedValue = VehicleAttributeValue::query()
            ->where('owner_id', $copyId)
            ->where('owner_type', 'vehicle-trim')
            ->where('attribute_id', $attribute->id)
            ->first();

        $this->assertNotNull($copiedValue);
        $this->assertEquals('Premium Package', $copiedValue->value_text);

        // Verify original still has its values
        $this->assertEquals(1,
            VehicleAttributeValue::query()
                ->where('owner_id', $trim->id)
                ->where('attribute_id', $attribute->id)
                ->count()
        );
    }

    public function testShowTrimWithNoAttributesReturnsEmptyExtra()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $trim = VehicleTrim::query()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'No Attributes Trim',
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.vehicle-trims.show', $trim));

        $response->assertStatus(200);
        $this->assertArrayHasKey('extra', $response->json());
        $this->assertEmpty($response->json('extra'));
    }
}
