<?php

namespace Tests\Feature\Controllers;

use App\Jobs\SyncContentToTemplate;
use App\TemplateRepository;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\Page;
use Mtc\MercuryDataModels\Template;
use Mtc\MercuryDataModels\VehicleOffer;
use Tests\DatabaseTestCase;
use Tests\UserForTenant;

class TemplateControllerTest extends DatabaseTestCase
{
    use UserForTenant;


    public function testIndex()
    {
        Template::query()->delete();
        Template::factory(5)->create();
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->withoutExceptionHandling()
            ->getJson(route('content.templates.index'));

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

    public function testShow()
    {
        $template = Template::factory()->create();
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('content.templates.show', $template));

        $response->assertStatus(200);
        $this->assertArrayHasKey('template', $response->json());
        $this->assertArrayHasKey('global_content', $response->json());
        $this->assertArrayHasKey('elements', $response->json());
        $this->assertArrayHasKey('comments', $response->json());
    }

    public function testShowReturnsLockedMetaValue()
    {
        $template = Template::factory()->create(['meta' => ['locked' => true]]);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('content.templates.show', $template));

        $response->assertStatus(200);
        $this->assertTrue($response->json('template.meta.locked'));
    }

    public function testShowDefaultsLockedMetaValueToFalse()
    {
        $template = Template::factory()->create(['meta' => []]);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('content.templates.show', $template));

        $response->assertStatus(200);
        $this->assertFalse($response->json('template.meta.locked'));
    }

    public function testUsage()
    {
        $template = Template::factory()->create();
        $pages = Page::factory(3)->create(['template_id' => $template->id]);
        Page::factory(3)->create(['template_id' => null]);
        $offers = VehicleOffer::factory(4)->create(['template_id' => $template->id]);

        $response = $this->actingAs($this->getUser(false))
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.templates.usage', $template));

        $response->assertStatus(200);
        $this->assertCount(7, $response->json());
        $pages->each(fn ($page) => $this->assertTrue(collect($response->json())->where('type', 'page')->where('id', $page->id)->isNotEmpty()));
        $offers->each(fn ($offer) => $this->assertTrue(collect($response->json())->where('type', 'offer')->where('id', $offer->id)->isNotEmpty()));
    }

    public function testSync()
    {
        Queue::fake();
        $template = Template::factory()->create();
        $page = Page::factory()->create(['template_id' => $template->id]);
        Page::factory(3)->create(['template_id' => null]);
        $offer = VehicleOffer::factory()->create(['template_id' => $template->id]);

        $response = $this->actingAs($this->getUser(false))
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.templates.sync-usage', $template));
        $response->assertStatus(200);
        Queue::assertPushed(SyncContentToTemplate::class);

    }

    public function testSyncProcess()
    {
        $template = Template::factory()->create();
        $page = Page::factory()->create(['template_id' => $template->id]);
        Page::factory(3)->create(['template_id' => null]);
        $offer = VehicleOffer::factory()->create(['template_id' => $template->id]);

        Bus::fake();
        $response = $this->actingAs($this->getUser(false))
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.templates.sync-usage', $template));
        $response->assertStatus(200);
        Bus::assertDispatched(SyncContentToTemplate::class);
        Bus::assertDispatchedTimes(SyncContentToTemplate::class, 2);
    }

    public function testUserCanModifyUnlockedTemplate()
    {
        $repository = new TemplateRepository();
        $template = Template::factory()->create(['meta' => []]);

        $this->assertTrue($repository->userCanModify($template, null));
    }

    public function testUserCanModifyLockedTemplateRequiresMtcRole()
    {
        $repository = new TemplateRepository();
        $template = Template::factory()->create(['meta' => ['locked' => true]]);

        $this->assertTrue($repository->userCanModify($template, $this->getUser('mtc')));
    }

    public function testUserCannotModifyLockedTemplateWithoutMtcRole()
    {
        $repository = new TemplateRepository();
        $template = Template::factory()->create(['meta' => ['locked' => true]]);

        $this->assertFalse($repository->userCanModify($template, null));
    }

    public function testDestroyBlockedWhenTemplateLockedAndUserMissingMtcRole()
    {
        $template = Template::factory()->create(['meta' => ['locked' => true]]);
        $user = $this->getUser('Administrator');
        $user->givePermissionTo('edit-templates');

        $response = $this->actingAs($user)
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('content.templates.destroy', $template));

        $response->assertStatus(403);
        $this->assertTrue(Template::query()->where('id', $template->id)->exists());
    }

    public function testDestroyAllowedWhenTemplateLockedAndUserHasMtcRole()
    {
        $template = Template::factory()->create(['meta' => ['locked' => true]]);

        $response = $this->actingAs($this->getUser('mtc'))
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('content.templates.destroy', $template));

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