<?php

namespace Tests\Feature;

use App\Facades\Settings;
use App\Notifications\PageVersionMarkedChangesRequested;
use App\Notifications\PageVersionMarkedToBeReviewed;
use App\PageRepository;
use Database\Seeders\MercuryTheme\ContentElementSeeder;
use Database\Seeders\MercuryTheme\TemplateSeeder;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Notification;
use Mockery\MockInterface;
use Mtc\ContentManager\Models\Page;
use Mtc\MercuryDataModels\PageVersion;
use Tests\DatabaseTestCase;
use Tests\UserForTenant;

class PageRepositoryTest extends DatabaseTestCase
{
    use UserForTenant;

    public function testHasVersioning()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'pages-versioning-enabled',
            'value' => false,
            'type' => 'boolean',
        ]);
        tenant()->tier = 'lite';
        $this->assertFalse($this->repository()->hasVersioning());

        tenant()->tier = 'pro';
        $this->assertFalse($this->repository()->hasVersioning());
        Settings::update('pages-versioning-enabled', true);
        $this->assertTrue($this->repository()->hasVersioning());
    }

    public function testContentUpdateAdVersionSaving()
    {
        tenant()->tier = 'pro';
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'value' => true,
            'type' => 'bool',
            'config_key' => 'pages-versioning-enabled',
        ]);
        $this->seed(ContentElementSeeder::class);
        $this->seed(TemplateSeeder::class);
        $template = \Mtc\MercuryDataModels\Template::query()->where('slug', 'offers-list')->first();
        $page = Page::factory()->create([
            'title' => 'foo',
            'template_id' => $template->id,
        ]);

        $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('content.pages.sync-with-template', $page))
            ->assertStatus(201);

        $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('content.pages.restore-version', [$page, $page->versions()->first()]));

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('content.pages.show', $page));

        $pageData = $response->json('page');

        $pageData['content'][0]['children'][0]['content'] = 'foo';
        $pageData['content'][0]['children'][1]['content'] = 'baz bar';
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('content.pages.update', $page), $pageData);

        $response->assertStatus(200);
        $this->assertEquals('foo', $response->json('page.content.0.children.0.content'));
        $this->assertEquals('baz bar', $response->json('page.content.0.children.1.content'));
        $this->assertEquals(2, $page->versions()->count());
    }

    public function testMarkVersionChangesRequested()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'value' => true,
            'type' => 'bool',
            'config_key' => 'pages-versioning-content-review-mode',
        ]);
        Auth::setUser($this->getUser());
        $page = Page::factory()->create();
        $version = PageVersion::factory()->create([
            'page_id' => $page->id,
            'author_id' => $this->getUser()->id
        ]);

        $this->partialMock(PageRepository::class, function (MockInterface $mock) use ($page, $version) {
            $mock->shouldReceive('markVersionAsChangesRequested')
                ->andReturnUsing(function () use ($page, $version) {
                    $data = new \Mtc\ContentManager\PageRepository($page, $version)
                        ->markVersionAsChangesRequested($page->id, $version->id);
                    $this->getUser()->notify(
                        new PageVersionMarkedChangesRequested($data, Auth::user())
                    );
                    return $data;
                });
        });

        Notification::fake();
        $this->repository()->markVersionAsChangesRequested($page->id, $version->id);
        Notification::assertSentTo([$this->getUser()], PageVersionMarkedChangesRequested::class);
        $version->refresh();
        $this->assertTrue($version->request_changes);
    }

    public function testMarkVersionForReview()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'value' => true,
            'type' => 'bool',
            'config_key' => 'pages-versioning-content-review-mode',
        ]);
        //$this->getUser()->tenants()->attach(tenant(), ['role' => 'Administrator']);
        $page = Page::factory()->create();
        $version = PageVersion::factory()->create([
            'page_id' => $page->id,
            'author_id' => $this->getUser()->id
        ]);

        $this->partialMock(PageRepository::class, function (MockInterface $mock) use ($page, $version) {
            $mock->shouldReceive('markVersionForReview')
                ->andReturnUsing(function () use ($page, $version) {
                    $data = new \Mtc\ContentManager\PageRepository($page, $version)
                        ->markVersionForReview($page->id, $version->id);
                    $this->getUser()->notify(new PageVersionMarkedToBeReviewed($data));
                    return $data;
                });
        });

        Notification::fake();
        $this->repository()->markVersionForReview($page->id, $version->id);
        Notification::assertSentTo([$this->getUser()], PageVersionMarkedToBeReviewed::class);
        $version->refresh();
        $this->assertTrue($version->pending_review);
    }

    public function testTemplateChange()
    {
        tenant()->tier = 'pro';
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'value' => true,
            'type' => 'bool',
            'config_key' => 'pages-versioning-enabled',
        ]);
        $this->seed(ContentElementSeeder::class);
        $this->seed(TemplateSeeder::class);
        $template = \Mtc\MercuryDataModels\Template::query()->where('slug', 'offers-list')->first();
        $page = Page::factory()->create([
            'title' => 'foo',
        ]);


        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('content.pages.update', $page), [
                'title' => $page->title,
                'status' => $page->status,
                'slug' => $page->slug,
                'template_id' => $template->id,
                'seo' => [
                    'title' => 'foo',
                    'description' => 'baz bar',
                ],
                'content' => [],
            ]);

        $response->assertStatus(200);
        $this->assertEquals($template->id, $response->json('page.template_id'));

    }

    private function repository(): PageRepository
    {
        return App::make(PageRepository::class);
    }
}
