<?php

namespace Tests\Tenant;

use App\Jobs\RunImportConditionJob;
use App\Models\ImportCondition;
use App\Models\ImportMap;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\Label;
use Mtc\MercuryDataModels\Setting;
use Mtc\MercuryDataModels\VehicleAttribute;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class ImportConditionControllerTest extends TenantTestCase
{
    use UserForTenant;

    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testIndex()
    {
        ImportCondition::factory(3)->create();

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

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

    public function testStore()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.store'), [
                'provider' => 'foo'
            ]);

        $response->assertStatus(201);
        $this->assertEquals('foo', $response->json('provider'));
        $this->assertTrue(ImportCondition::query()->where('provider', 'foo')->exists());

    }

    public function testUpdate()
    {
        $condition = ImportCondition::factory()->create(['provider' => 'foo']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.import-conditions.update', $condition->id), [
                'provider' => 'baz',
                'active' => true,
                'do_not_publish' => true,
                'rules' => [
                    [
                        'id' => Str::random(12),
                        'field' => 'baz',
                        'condition' => '=',
                        'value' => 'faz',
                    ]
                ]
            ]);

        $condition->refresh();
        $response->assertStatus(200);
        $this->assertEquals('baz', $condition->provider);
        $this->assertEquals(1, $condition->rules()->count());
        $rule = $condition->rules()->first();
        $this->assertEquals('baz', $rule->field);
        $this->assertEquals('=', $rule->condition);
        $this->assertEquals('faz', $rule->value);

    }

    public function testShow()
    {
        $condition = ImportCondition::factory()->create(['provider' => 'foo']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.import-conditions.show', $condition->id));

        $response->assertStatus(200);
        $this->assertEquals($condition->id, $response->json('id'));
        $this->assertEquals('foo', $response->json('provider'));

    }

    public function testDelete()
    {
        $condition = ImportCondition::factory()->create(['provider' => 'foo']);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('tenant.import-conditions.destroy', $condition->id));

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

    public function testGetProviders()
    {
        $map = ImportMap::factory()->create();
        Setting::query()->create([
            'tab' => 'foo',
            'section' => 'foo',
            'group' => 'foo',
            'name' => 'foo',
            'config_key' => 'stock-file-enabled',
            'type' => 'boolean',
            'value' => true
        ]);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.import-conditions.get-providers'));

        $response->assertStatus(200);
        $this->assertArrayHasKey('import_maps', $response->json());
        $this->assertArrayHasKey('providers', $response->json());
        $this->assertCount(1, $response->json('import_maps'));
        $this->assertEquals($map->id, $response->json('import_maps.0.id'));
        $this->assertEquals($map->name, $response->json('import_maps.0.name'));
        $this->assertCount(1, $response->json('providers'));
        $this->assertEquals('import-map', $response->json('providers.0.id'));
    }

    public function testGetRules()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.get-rules'), [
                'field' => 'make_id',
            ]);

        $response->assertStatus(200);
        $this->assertArrayHasKey('fields', $response->json());
        $this->assertArrayHasKey('conditions', $response->json());
        $this->assertArrayHasKey('values', $response->json());
    }

    public function testGetRulesIncludesLabelField()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.get-rules'), []);

        $response->assertStatus(200);
        $fieldIds = collect($response->json('fields'))->pluck('id')->all();
        $this->assertContains('label', $fieldIds);
    }

    public function testGetRulesReturnsActiveLabelsAsValues()
    {
        $active = Label::factory()->create(['name' => 'Hot Deals', 'active' => true]);
        $inactive = Label::factory()->create(['name' => 'Old', 'active' => false]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.get-rules'), [
                'field' => 'label',
            ]);

        $response->assertStatus(200);
        $valueIds = collect($response->json('values'))->pluck('id')->all();
        $this->assertContains($active->id, $valueIds);
        $this->assertNotContains($inactive->id, $valueIds);
    }

    public function testGetRulesIncludesConditionField()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.get-rules'), []);

        $response->assertStatus(200);
        $fieldIds = collect($response->json('fields'))->pluck('id')->all();
        $this->assertContains('condition', $fieldIds);
    }

    public function testGetRulesIncludesVehicleAttributes()
    {
        VehicleAttribute::factory()->create([
            'name' => 'Contact Name',
            'slug' => 'contact_name',
            'type' => 'text',
            'model' => 'vehicle',
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.get-rules'), [
                'field' => 'attribute.contact_name',
            ]);

        $response->assertStatus(200);
        $field = collect($response->json('fields'))->firstWhere('id', 'attribute.contact_name');
        $this->assertNotNull($field);
        $this->assertEquals('Contact Name', $field['name']);
        // Attribute fields behave as free-text value fields, so support in/not_in...
        $conditionIds = collect($response->json('conditions'))->pluck('id')->all();
        $this->assertContains('in', $conditionIds);
        $this->assertContains('not_in', $conditionIds);
        // ...but not numeric comparisons or the raw-column "exists" check.
        $this->assertNotContains('>', $conditionIds);
        $this->assertNotContains('exists', $conditionIds);
    }

    public function testRunRequiresRules()
    {
        Queue::fake();
        $condition = ImportCondition::factory()->create(['provider' => 'autograb']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.run', $condition->id));

        $response->assertStatus(422);
        Queue::assertNotPushed(RunImportConditionJob::class);
    }

    public function testRunDispatchesJob()
    {
        Queue::fake();
        $condition = ImportCondition::factory()->create(['provider' => 'autograb']);
        $condition->rules()->create([
            'field' => 'attribute.contact_name',
            'condition' => 'in',
            'value' => 'Bad Dealer',
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.run', $condition->id));

        $response->assertStatus(200);
        Queue::assertPushed(RunImportConditionJob::class);
    }

    public function testGetRulesReturnsNewAndUsedAsConditionValues()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.import-conditions.get-rules'), [
                'field' => 'condition',
            ]);

        $response->assertStatus(200);
        $values = collect($response->json('values'));
        $this->assertEquals(['New', 'Used'], $values->pluck('name')->all());
        $this->assertEquals([1, 0], $values->pluck('id')->all());
    }
}
