<?php

namespace Tests\Tenant;

use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;
use Mtc\ContentManager\Models\Media;
use Mtc\MercuryDataModels\CatalogOffer;
use Mtc\MercuryDataModels\CatalogOfferRule;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class CatalogOfferControllerTest extends TenantTestCase
{
    use UserForTenant;

    public function testIndex()
    {
        CatalogOffer::factory(5)->create();
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson('/api/catalog-offers');

        $response->assertStatus(200);
        $this->assertArrayHasKey('data', $response->json());
        $this->assertIsArray($response->json('data'));
        $this->assertCount(5, $response->json('data'));
        $this->assertArrayHasKey('title', $response->json('data.0'));
        $this->assertArrayHasKey('link', $response->json('data.0'));
        $this->assertArrayHasKey('id', $response->json('data.0'));
        $this->assertArrayHasKey('type', $response->json('data.0'));
    }

    public function testIndexFiltersByVehicleType()
    {
        CatalogOffer::factory(3)->forVehicles()->create();
        CatalogOffer::factory(2)->forNewCars()->create();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson('/api/catalog-offers?type=vehicle');

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

        foreach ($response->json('data') as $offer) {
            $this->assertEquals('vehicle', $offer['type']);
        }
    }

    public function testIndexFiltersByNewCarType()
    {
        CatalogOffer::factory(3)->forVehicles()->create();
        CatalogOffer::factory(2)->forNewCars()->create();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson('/api/catalog-offers?type=new_car');

        $response->assertStatus(200);
        $this->assertCount(2, $response->json('data'));

        foreach ($response->json('data') as $offer) {
            $this->assertEquals('new_car', $offer['type']);
        }
    }

    public function testShow()
    {
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.catalog-offers.show', $offer));

        $response->assertStatus(200);
        $this->assertIsArray($response->json());
        $this->assertEquals('foo baz bar', $response->json('name'));
        $this->assertArrayHasKey('media', $response->json());
        $this->assertArrayHasKey('subtitle', $response->json());
        $this->assertArrayHasKey('link', $response->json());
        $this->assertArrayHasKey('button_text', $response->json());
        $this->assertArrayHasKey('active', $response->json());
    }
    public function testStore()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.catalog-offers.store'), [
                'name' => 'foo baz bar'
            ]);

        $response->assertStatus(201);
        $this->assertEquals('foo baz bar', $response->json('name'));
        $this->assertEquals(0, $response->json('active'));
        $this->assertEquals('vehicle', $response->json('type'));
    }

    public function testStoreWithNewCarType()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.catalog-offers.store'), [
                'name' => 'New Car Offer',
                'type' => 'new_car'
            ]);

        $response->assertStatus(201);
        $this->assertEquals('New Car Offer', $response->json('name'));
        $this->assertEquals('new_car', $response->json('type'));
    }

    public function testUpdate()
    {
        Queue::fake();
        $media = Media::factory()->create();
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.catalog-offers.update', $offer), [
                'name' => 'lorem ipsum',
                'active' => true,
                'media' => [$media->id],
                'subtitle' => 'foo faz',
                'link' => '/foo-faz',
            ]);

        $response->assertStatus(200);
        $this->assertIsArray($response->json());
        $this->assertEquals('lorem ipsum', $response->json('name'));
        $offer->refresh();
        $this->assertTrue((bool)$offer->active);
        $this->assertEquals('foo faz', $offer->subtitle);
        $this->assertEquals('/foo-faz', $offer->link);
        $this->assertEquals(1, $offer->mediaUses()->count());
    }

    public function testDestroy()
    {
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('tenant.catalog-offers.destroy', $offer));

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

    public function testShowIncludesRules()
    {
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => '123',
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.catalog-offers.show', $offer));

        $response->assertStatus(200);
        $this->assertArrayHasKey('rules', $response->json());
        $this->assertCount(1, $response->json('rules'));
        $this->assertEquals('make_id', $response->json('rules.0.field'));
        $this->assertEquals('=', $response->json('rules.0.condition'));
        $this->assertEquals('123', $response->json('rules.0.value'));
    }

    public function testUpdateWithRules()
    {
        Queue::fake();
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.catalog-offers.update', $offer), [
                'name' => 'lorem ipsum',
                'active' => true,
                'subtitle' => 'foo faz',
                'link' => '/foo-faz',
                'rules' => [
                    [
                        'id' => Str::random(12),
                        'field' => 'make_id',
                        'condition' => '=',
                        'value' => '456',
                    ],
                    [
                        'id' => Str::random(12),
                        'field' => 'price',
                        'condition' => '>',
                        'value' => '10000',
                    ],
                ]
            ]);

        $response->assertStatus(200);
        $offer->refresh();
        $this->assertEquals(2, $offer->rules()->count());

        $rules = $offer->rules()->get();
        $this->assertEquals('make_id', $rules[0]->field);
        $this->assertEquals('=', $rules[0]->condition);
        $this->assertEquals('456', $rules[0]->value);
        $this->assertEquals('price', $rules[1]->field);
        $this->assertEquals('>', $rules[1]->condition);
        $this->assertEquals('10000', $rules[1]->value);
    }

    public function testUpdateRemovesDeletedRules()
    {
        Queue::fake();
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);

        // Create initial rules
        $rule1 = CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => '123',
        ]);
        $rule2 = CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'price',
            'condition' => '>',
            'value' => '5000',
        ]);

        $this->assertEquals(2, $offer->rules()->count());

        // Update with only one rule (removing rule2)
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.catalog-offers.update', $offer), [
                'name' => 'lorem ipsum',
                'active' => true,
                'subtitle' => 'foo faz',
                'link' => '/foo-faz',
                'rules' => [
                    [
                        'id' => $rule1->id,
                        'field' => 'make_id',
                        'condition' => '!=',
                        'value' => '789',
                    ],
                ]
            ]);

        $response->assertStatus(200);
        $offer->refresh();
        $this->assertEquals(1, $offer->rules()->count());

        $rule = $offer->rules()->first();
        $this->assertEquals('make_id', $rule->field);
        $this->assertEquals('!=', $rule->condition);
        $this->assertEquals('789', $rule->value);

        // Verify rule2 was deleted
        $this->assertFalse(CatalogOfferRule::query()->where('id', $rule2->id)->exists());
    }

    public function testUpdateWithRuleArrayValueIsJsonEncoded()
    {
        Queue::fake();
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.catalog-offers.update', $offer), [
                'name' => 'lorem ipsum',
                'active' => true,
                'subtitle' => 'foo faz',
                'link' => '/foo-faz',
                'rules' => [
                    [
                        'id' => Str::random(12),
                        'field' => 'dealership_id',
                        'condition' => 'in',
                        'value' => [2, 5, 9, 10],
                    ],
                ]
            ]);

        $response->assertStatus(200);
        $offer->refresh();
        $this->assertEquals(1, $offer->rules()->count());

        $rule = $offer->rules()->first();
        $this->assertEquals('dealership_id', $rule->field);
        $this->assertEquals('in', $rule->condition);
        $this->assertEquals('[2,5,9,10]', $rule->value);
    }

    public function testUpdateWithEmptyRulesRemovesAllRules()
    {
        Queue::fake();
        $offer = CatalogOffer::factory()->create(['name' => 'foo baz bar']);

        // Create initial rules
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => '123',
        ]);

        $this->assertEquals(1, $offer->rules()->count());

        // Update with empty rules array
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.catalog-offers.update', $offer), [
                'name' => 'lorem ipsum',
                'active' => true,
                'subtitle' => 'foo faz',
                'link' => '/foo-faz',
                'rules' => []
            ]);

        $response->assertStatus(200);
        $offer->refresh();
        $this->assertEquals(0, $offer->rules()->count());
    }
}
