<?php

namespace Tests\Tenant;

use Carbon\Carbon;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\GlobalContent;
use Mtc\MercuryDataModels\Jobs\TrackResourceView;
use Mtc\MercuryDataModels\Page;
use Mtc\MercuryDataModels\ResourceView;
use Mtc\MercuryDataModels\Seo404;
use Tests\TenantTestCase;

class PageControllerTest extends TenantTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        Queue::fake();
    }

    public function testShowPageEndpoint()
    {
        Page::factory()->create(['title' => 'foo baz bar', 'slug' => 'home', 'status' => 'published']);

        $response = $this
            ->getJson(route('pages.show', 'home'));
        $response->assertStatus(200);

        $this->assertEquals('home', $response->json('slug'));
        $this->assertEquals('foo baz bar', $response->json('title'));
    }

    public function testShowGlobalContentEndpoint()
    {
        GlobalContent::factory()->create([
            'name' => 'foo baz bar',
            'slug' => 'foo',
            'content' => [
                'foo' => [
                    'id' => 1,
                    'content' => 'baz'
                ]
            ]
        ]);

        $response = $this
            ->getJson(route('pages.get-global', 'faz'));
        $response->assertStatus(404);

        $response = $this
            ->getJson(route('pages.get-global', 'foo'));
        $response->assertStatus(200);

        $this->assertEquals('baz', $response->json('foo.content'));
    }

    public function testGetSiteEndpoint()
    {
        Page::factory()->create(['title' => 'foo baz bar', 'slug' => 'home']);

        $response = $this
            ->getJson(route('get-site'));
        $response->assertStatus(200);

        $this->assertEquals(tenant('id'), $response->json('id'));
    }
    public function testPagePreviewRestriction()
    {
        $page = Page::factory()->create([
            'title' => 'foo baz bar',
            'slug' => 'home',
            'status' => 'published'
        ]);

        $response = $this
            ->getJson(route('pages.show', 'home'));
        $response->assertStatus(200);
        $response = $this
            ->getJson(route('pages.show', 'home') . '?a=1231231231');
        $response->assertStatus(200);

        $page->update(['status' => 'draft']);
        $response = $this
            ->getJson(route('pages.show', 'home'));
        $response->assertStatus(401);

        $access = base64_encode($page->id . '-' . $page->slug);
        $response = $this
            ->getJson(route('pages.show', 'home') . '?a=' . $access);
        $response->assertStatus(200);
    }

    public function testPagePublishDate()
    {
        $page = Page::factory()->create([
            'title' => 'foo baz bar',
            'slug' => 'home',
            'status' => 'published',
            'published_at' => Carbon::now()->addHour()
        ]);

        $response = $this->getJson(route('pages.show', 'home'));
        $response->assertStatus(404);

        $page->update(['published_at' => Carbon::now()->subHours(2)]);
        $response = $this->getJson(route('pages.show', 'home'));
        $response->assertStatus(200);
    }

    public function test404Tracking()
    {
        $this->assertEquals(0, Seo404::query()->where('path', '/foo-faz')->count());
        $response = $this
            ->withHeaders(['x-path' => '/foo-faz'])
            ->getJson(route('pages.track-404'));

        $response->assertStatus(200);

        $this->assertEquals(1, Seo404::query()->where('path', '/foo-faz')->count());
        $this->assertEquals(1, Seo404::query()->where('path', '/foo-faz')->pluck('hits')->first());

        $response = $this
            ->withHeaders(['x-path' => '/foo-faz'])
            ->getJson(route('pages.track-404'));
        $this->assertEquals(1, Seo404::query()->where('path', '/foo-faz')->count());
        $this->assertEquals(2, Seo404::query()->where('path', '/foo-faz')->pluck('hits')->first());
    }

    public function testPageViewTrackingForPublishedPage()
    {
        $page = Page::factory()->create([
            'title' => 'Test Page',
            'slug' => 'test-page',
            'status' => 'published'
        ]);

        $response = $this->getJson(route('pages.show', 'test-page'));
        $response->assertStatus(200);

        Queue::assertPushed(TrackResourceView::class, function ($job) use ($page) {
            return true;
        });
    }

    public function testPageViewTrackingNotDispatchedForDraftPage()
    {
        $page = Page::factory()->create([
            'title' => 'Draft Page',
            'slug' => 'draft-page',
            'status' => 'draft'
        ]);

        $response = $this->getJson(route('pages.show', 'draft-page'));
        $response->assertStatus(401);

        Queue::assertNotPushed(TrackResourceView::class);
    }

    public function testPageViewTrackingNotDispatchedForPreviewWithAccessKey()
    {
        $page = Page::factory()->create([
            'title' => 'Preview Page',
            'slug' => 'preview-page',
            'status' => 'published'
        ]);

        $accessKey = base64_encode($page->id . '-' . $page->slug);
        $response = $this->getJson(route('pages.show', 'preview-page') . '?a=' . $accessKey);
        $response->assertStatus(200);

        Queue::assertNotPushed(TrackResourceView::class);
    }

    public function testTrendingPagesEndpoint()
    {
        $page1 = Page::factory()->create([
            'category' => 'blog',
            'published_at' => Carbon::now()->subDays(5),
            'status' => 'published',
        ]);

        $page2 = Page::factory()->create([
            'category' => 'blog',
            'published_at' => Carbon::now()->subDays(4),
            'status' => 'published',
        ]);

        ResourceView::query()->create([
            'viewable_type' => 'page',
            'viewable_id' => $page1->id,
            'date' => Carbon::now()->format('Y-m-d'),
            'hits' => 10,
        ]);

        ResourceView::query()->create([
            'viewable_type' => 'page',
            'viewable_id' => $page2->id,
            'date' => Carbon::now()->format('Y-m-d'),
            'hits' => 50,
        ]);

        $response = $this->getJson(route('pages.trending', ['type' => 'blog', 'page_count' => 5]));
        $response->assertStatus(200);
        $this->assertCount(2, $response->json());
        $this->assertEquals('/blog/' . $page2->slug, $response->json('0.url'));
    }

    public function testTrendingPagesWithAuthorSlugFilter()
    {
        // Source page whose slug is used to resolve the author_id
        $sourcePage = Page::factory()->create([
            'category' => 'blog',
            'author_id' => 1,
            'slug' => 'author-source',
            'published_at' => Carbon::now()->subDays(1),
            'status' => 'published',
        ]);

        Page::factory()->create([
            'category' => 'blog',
            'author_id' => 1,
            'published_at' => Carbon::now()->subDays(1),
            'status' => 'published',
        ]);

        $otherPage = Page::factory()->create([
            'category' => 'blog',
            'author_id' => 2,
            'published_at' => Carbon::now()->subDays(1),
            'status' => 'published',
        ]);

        $response = $this->getJson(route('pages.trending', [
            'type'        => 'blog',
            'page_slug'   => 'author-source',
            'filter_type' => 'author',
        ]));

        $response->assertStatus(200);
        // Only pages with author_id=1 should be returned, excluding the source page
        $this->assertCount(1, $response->json());
        $ids = collect($response->json())->pluck('id')->toArray();
        $this->assertNotContains($otherPage->id, $ids);
        $this->assertNotContains($sourcePage->id, $ids);
    }

    public function testTrendingPagesRequiresType()
    {
        $response = $this->getJson(route('pages.trending'));
        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['type']);
    }

    public function testTrendingPagesWithZeroDays()
    {
        $page = Page::factory()->create([
            'category' => 'blog',
            'published_at' => Carbon::now()->subDays(5),
            'status' => 'published',
        ]);

        ResourceView::query()->create([
            'viewable_type' => 'page',
            'viewable_id' => $page->id,
            'date' => Carbon::now()->subDays(365)->format('Y-m-d'),
            'hits' => 100,
        ]);

        $response = $this->getJson(route('pages.trending', ['type' => 'blog', 'days' => 0]));
        $response->assertStatus(200);
        $this->assertCount(1, $response->json());
    }

    public function testResourceViewRecordCreation()
    {
        $page = Page::factory()->create([
            'title' => 'View Test Page',
            'slug' => 'view-test-page',
            'status' => 'published'
        ]);

        $response = $this->getJson(route('pages.show', 'view-test-page'));
        $response->assertStatus(200);

        Queue::assertPushed(TrackResourceView::class);
    }
}
