<?php

namespace Tests\Tenant;

use Mtc\MercuryDataModels\VehicleType;
use Mtc\MercuryDataModels\Enums\SocialMediaPlatform;
use Mtc\MercuryDataModels\Franchise;
use Mtc\MercuryDataModels\VehicleMake;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class FranchiseControllerTest extends TenantTestCase
{
    use UserForTenant;

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

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

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

    public function testStore()
    {
        $socials = [
            'facebook' => 'https://facebook.com/test',
            'instagram' => 'https://instagram.com/test',
        ];

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.franchises.store'), [
                'name' => 'foo',
                'socials' => $socials,
            ]);

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

        $franchise = Franchise::query()->where('name', 'foo')->first();
        $this->assertEquals('https://facebook.com/test', $franchise->socials['facebook']);
        $this->assertEquals('https://instagram.com/test', $franchise->socials['instagram']);
    }

    public function testUpdate()
    {
        $make = VehicleMake::factory()->create();
        $franchise = Franchise::factory()->create(['name' => 'foo']);

        $socials = [
            'facebook' => 'https://facebook.com/updated',
            'youtube' => 'https://youtube.com/updated',
        ];

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.franchises.update', $franchise->id), [
                'name' => 'baz',
                'make_id' => $make->id,
                'primary_colour' => 'A1B2C3',
                'secondary_colour' => 'AABBCC',
                'socials' => $socials,
            ]);

        $franchise->refresh();
        $response->assertStatus(200);
        $this->assertEquals('AABBCC', $response->json('franchise.secondary_colour'));
        $this->assertEquals('AABBCC', $franchise->secondary_colour);
        $this->assertEquals('baz', $franchise->name);
        $this->assertEquals($make->id, $franchise->make_id);
        $this->assertEquals('https://facebook.com/updated', $franchise->socials['facebook']);
        $this->assertEquals('https://youtube.com/updated', $franchise->socials['youtube']);
    }

    public function testShow()
    {
        $franchise = Franchise::factory()->create(['name' => 'foo']);

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

        $response->assertStatus(200);
        $this->assertEquals($franchise->id, $response->json('franchise.id'));
        $this->assertEquals('foo', $response->json('franchise.name'));
        $this->assertArrayHasKey('makes', $response->json());
        $this->assertArrayHasKey('vehicle_types', $response->json());

        // Options are filtered by the `enabled-vehicle-types` setting (defaults to car + lcv).
        $typeIds = collect($response->json('vehicle_types'))->pluck('id')->all();
        $this->assertContains(VehicleType::CAR->value, $typeIds);
        $this->assertContains(VehicleType::LCV->value, $typeIds);
        $this->assertNotContains(VehicleType::MOTORCYCLE->value, $typeIds);
    }

    public function testUpdateVehicleType()
    {
        $franchise = Franchise::factory()->create(['name' => 'foo']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.franchises.update', $franchise->id), [
                'name' => 'foo',
                'primary_colour' => '000000',
                'secondary_colour' => 'FFFFFF',
                'vehicle_type' => VehicleType::LCV->value,
            ]);

        $response->assertStatus(200);
        $this->assertEquals(VehicleType::LCV->value, $response->json('franchise.vehicle_type'));
        $this->assertEquals(VehicleType::LCV->value, $franchise->refresh()->vehicle_type);
    }

    public function testVehicleTypeValidation()
    {
        $franchise = Franchise::factory()->create(['name' => 'foo']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.franchises.update', $franchise->id), [
                'name' => 'foo',
                'vehicle_type' => 'spaceship',
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['vehicle_type']);
    }

    public function testDelete()
    {
        $franchise = Franchise::factory()->create(['name' => 'foo']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('tenant.franchises.destroy', $franchise->id));

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

    public function testCopy()
    {
        $socials = [
            'facebook' => 'https://facebook.com/original',
            'twitter' => 'https://twitter.com/original',
        ];
        $franchise = Franchise::factory()->create(['name' => 'foo', 'socials' => $socials]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.franchise.copy', $franchise->id), [
                'name' => 'baz bar',
            ]);

        $this->assertEquals(2, Franchise::query()->count());
        $this->assertNotEquals($franchise->id, $response->json('franchise.id'));
        $this->assertEquals('baz bar', $response->json('franchise.name'));
        $this->assertEquals($franchise->secondary_colour, $response->json('franchise.secondary_colour'));

        $copy = Franchise::query()->where('name', 'baz bar')->first();
        $this->assertEquals('https://facebook.com/original', $copy->socials['facebook']);
        $this->assertEquals('https://twitter.com/original', $copy->socials['twitter']);
    }

    public function testStoreSocialMediaFields()
    {
        $socials = collect(SocialMediaPlatform::values())
            ->mapWithKeys(fn ($platform) => [$platform => "https://{$platform}.com/testpage"])
            ->toArray();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.franchises.store'), [
                'name' => 'social franchise',
                'socials' => $socials,
            ]);

        $response->assertStatus(201);

        $franchise = Franchise::query()->where('name', 'social franchise')->first();
        foreach (SocialMediaPlatform::values() as $platform) {
            $this->assertEquals("https://{$platform}.com/testpage", $franchise->socials[$platform]);
        }
    }

    public function testUpdateSocialMediaFields()
    {
        $franchise = Franchise::factory()->create(['name' => 'social update test']);

        $socials = [
            'facebook' => 'https://facebook.com/newpage',
            'linkedin' => 'https://linkedin.com/company/newpage',
        ];

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.franchises.update', $franchise->id), [
                'name' => 'social update test',
                'socials' => $socials,
            ]);

        $response->assertStatus(200);

        $franchise->refresh();
        $this->assertEquals('https://facebook.com/newpage', $franchise->socials['facebook']);
        $this->assertEquals('https://linkedin.com/company/newpage', $franchise->socials['linkedin']);
    }

    public function testUpdateFavicon()
    {
        $franchise = Franchise::factory()->create(['name' => 'favicon test']);
        $path = tenant('id') . '/assets/favicon.ico';

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.franchises.update', $franchise->id), [
                'name' => $franchise->name,
                'primary_colour' => '000000',
                'secondary_colour' => 'FFFFFF',
                'favicon' => ['path' => $path, 'url' => "https://cdn.example/$path"],
            ]);

        $response->assertStatus(200);
        $this->assertEquals($path, $response->json('franchise.favicon.path'));
        $this->assertNotEmpty($response->json('franchise.favicon.url'));
        $this->assertEquals($path, $franchise->refresh()->getRawOriginal('favicon'));
    }

    public function testFaviconCanBeClearedByPassingNull()
    {
        $path = tenant('id') . '/assets/favicon.ico';
        $franchise = Franchise::factory()->create(['name' => 'clear', 'favicon' => $path]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.franchises.update', $franchise->id), [
                'name' => $franchise->name,
                'primary_colour' => '000000',
                'secondary_colour' => 'FFFFFF',
                'favicon' => ['path' => null, 'url' => ''],
            ]);

        $response->assertStatus(200);
        $this->assertNull($franchise->refresh()->getRawOriginal('favicon'));
    }

    public function testSocialMediaValidation()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->postJson(route('tenant.franchises.store'), [
                'name' => 'validation test',
                'socials' => [
                    'facebook' => 'not-a-valid-url',
                ],
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['socials.facebook']);
    }
}
