<?php

namespace Tests\Tenant;

use App\Exports\SeoDataExport;
use Illuminate\Http\UploadedFile;
use Maatwebsite\Excel\Facades\Excel;
use Mtc\MercuryDataModels\SeoData;
use Mtc\MercuryDataModels\SeoRedirect;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class SeoDataTest extends TenantTestCase
{
    use UserForTenant;

    public function testIndexPage()
    {
        SeoData::factory(4)->create();
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.seo_settings.data.index'));

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

    public function testStorePage()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.seo_settings.data.store'), [
            'path' => '/foo',
            'title' => 'baz bar',
            'description' => 'Lorem ipsum',
        ]);

        $response->assertStatus(201);
        $seo = SeoData::query()->where('path', '/foo')->first();
        $this->assertEquals('baz bar', $seo->title);
        $this->assertEquals('Lorem ipsum', $seo->description);
    }

    public function testUpdatePage()
    {
        $seo = SeoData::factory()->create();
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.seo_settings.data.update', $seo->id), [
            'path' => '/foo',
            'title' => 'baz bar',
            'description' => 'Lorem ipsum',
        ]);

        $response->assertStatus(200);
        $seo->refresh();
        $this->assertEquals('baz bar', $seo->title);
        $this->assertEquals('Lorem ipsum', $seo->description);
    }

    public function testDeletePage()
    {
        $seo = SeoData::factory()->create();
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('tenant.seo_settings.data.destroy', $seo->id));

        $response->assertStatus(200);
        $exists = SeoData::query()
            ->where('id', $seo->id)
            ->where(fn ($query) => $query->whereNotNull('title')->orWhereNotNull('description'))
            ->exists();
        $this->assertFalse($exists);
    }

    public function testExport()
    {
        Excel::fake();
        SeoData::factory(10)->create();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.seo_settings.data.export'));

        $response->assertStatus(200);
        Excel::assertDownloaded('seo_data.xlsx', function (SeoDataExport $export) {
            return $export->headings() === [
                'path',
                'title',
                'description',
                'heading',
                'canonical',
                'json_schema',
                'content_description',
            ];
        });
    }

    public function testImport()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.seo_settings.data.import'), [
                'truncate' => true,
                'file' => UploadedFile::fake()->createWithContent(
                    'seo_data_import_full.csv',
                    file_get_contents(dirname(__DIR__) . '/data/seo_data_import_full.csv')
                ),
            ]);

        $response->assertStatus(200);
        $this->assertEquals(2, SeoData::query()->count());

        $foo = SeoData::query()->where('path', '/foo')->first();
        $this->assertSame('baz', $foo->title);
        $this->assertSame('lorem ipsum', $foo->description);
        $this->assertSame('Foo Heading', $foo->heading);
        $this->assertSame('https://example.com/foo', $foo->canonical);
        $this->assertSame(
            '{"@context":"https://schema.org","@type":"WebPage","name":"Foo"}',
            $foo->json_schema
        );
        $this->assertSame('Foo content description', $foo->content_description);
    }

    public function testImportPreservesUnmappedFieldsWhenColumnsMissing()
    {
        SeoData::factory()->create([
            'path' => '/foo',
            'title' => 'original title',
            'description' => 'original description',
            'heading' => 'original heading',
            'canonical' => 'https://example.com/original',
            'json_schema' => '{"original":"schema"}',
            'content_description' => 'original content description',
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.seo_settings.data.import'), [
                'file' => UploadedFile::fake()->createWithContent(
                    'seo_data_import.csv',
                    file_get_contents(dirname(__DIR__) . '/data/seo_data_import.csv')
                ),
            ]);

        $response->assertStatus(200);

        $foo = SeoData::query()->where('path', '/foo')->first();
        $this->assertSame('baz', $foo->title);
        $this->assertSame('lorem ipsum', $foo->description);
        $this->assertSame('original heading', $foo->heading);
        $this->assertSame('https://example.com/original', $foo->canonical);
        $this->assertSame('{"original":"schema"}', $foo->json_schema);
        $this->assertSame('original content description', $foo->content_description);
    }

    public function testImportTruncateClearsAllSeoFields()
    {
        SeoData::factory()->create([
            'path' => '/keep-me',
            'title' => 'old title',
            'description' => 'old description',
            'heading' => 'old heading',
            'canonical' => 'https://example.com/old',
            'json_schema' => '{"old":"schema"}',
            'content_description' => 'old content description',
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.seo_settings.data.import'), [
                'truncate' => true,
                'file' => UploadedFile::fake()->createWithContent(
                    'seo_data_import.csv',
                    file_get_contents(dirname(__DIR__) . '/data/seo_data_import.csv')
                ),
            ]);

        $response->assertStatus(200);

        $untouched = SeoData::query()->where('path', '/keep-me')->first();
        $this->assertNotNull($untouched);
        $this->assertSame('/keep-me', $untouched->path);
        $this->assertNull($untouched->title);
        $this->assertNull($untouched->description);
        $this->assertNull($untouched->heading);
        $this->assertNull($untouched->canonical);
        $this->assertNull($untouched->json_schema);
        $this->assertNull($untouched->content_description);
    }

    public function testRedirectImport()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.seo_settings.redirects.import'), [
                'truncate' => true,
                'file' => UploadedFile::fake()->createWithContent(
                    'seo_redirects.csv',
                    file_get_contents(dirname(__DIR__) . '/data/seo_redirect_import.csv')
                ),
            ]);

        $response->assertStatus(200);
        $this->assertEquals(3, SeoRedirect::query()->count());
    }

    public function testJsonSchemaInvalid()
    {
        $seo = SeoData::factory()->create([
            'json_schema' => '{"abc":"123"}',
        ]);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.seo_settings.data.update', $seo->id), [
                'path' => '/foo',
                'title' => 'baz bar',
                'description' => 'Lorem ipsum',
                'jsonSchema' => 'xyz',
            ]);

        $response->assertStatus(422);
        $seo->refresh();
        $this->assertEquals('{"abc":"123"}', $seo->json_schema);
    }

    public function testJsonSchema()
    {
        $seo = SeoData::factory()->create([
            'json_schema' => '{"abc":"123"}',
        ]);
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.seo_settings.data.update', $seo->id), [
                'path' => '/foo',
                'title' => 'baz bar',
                'description' => 'Lorem ipsum',
                'jsonSchema' => '{"xyz":"456"}',
            ]);

        $response->assertStatus(200);
        $seo->refresh();
        $this->assertEquals('{"xyz":"456"}', $seo->json_schema);
    }

    public function testJsonSchemaNull()
    {
        $seo = SeoData::factory()->create();
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.seo_settings.data.update', $seo->id), [
                'path' => '/foo',
                'title' => 'baz bar',
                'description' => 'Lorem ipsum',
                'jsonSchema' => null,
            ]);

        $response->assertStatus(200);
    }
}
