<?php

namespace Tests\Feature\Controllers;

use Illuminate\Support\Facades\DB;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\User;
use Tests\DatabaseTestCase;
use Tests\UserForTenant;

class UserDealershipControllerTest extends DatabaseTestCase
{
    use UserForTenant;

    public function testShowReturnsUserDealershipsAndAllDealerships()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $dealership1 = Dealership::factory()->create(['name' => 'Alpha Motors']);
        $dealership2 = Dealership::factory()->create(['name' => 'Beta Motors']);
        $dealership3 = Dealership::factory()->create(['name' => 'Gamma Motors']);

        DB::table('user_dealerships')->insert([
            ['user_id' => $targetUser->id, 'dealership_id' => $dealership1->id],
            ['user_id' => $targetUser->id, 'dealership_id' => $dealership2->id],
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.settings.site-users.dealerships.show', $targetUser->id));

        $response->assertStatus(200);

        $this->assertIsArray($response->json('dealership_ids'));
        $this->assertCount(2, $response->json('dealership_ids'));
        $this->assertContains($dealership1->id, $response->json('dealership_ids'));
        $this->assertContains($dealership2->id, $response->json('dealership_ids'));

        $this->assertIsArray($response->json('dealerships'));
        $this->assertCount(3, $response->json('dealerships'));
    }

    public function testShowReturnsDealershipsOrderedByName()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        Dealership::factory()->create(['name' => 'Zulu Motors']);
        Dealership::factory()->create(['name' => 'Alpha Motors']);
        Dealership::factory()->create(['name' => 'Mike Motors']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.settings.site-users.dealerships.show', $targetUser->id));

        $response->assertStatus(200);

        $names = array_column($response->json('dealerships'), 'name');
        $this->assertEquals(['Alpha Motors', 'Mike Motors', 'Zulu Motors'], $names);
    }

    public function testShowReturnsEmptyDealershipIdsForUserWithNoAssignments()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.settings.site-users.dealerships.show', $targetUser->id));

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

    public function testShowFailsForUserNotOnTenant()
    {
        $targetUser = User::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.settings.site-users.dealerships.show', $targetUser->id));

        $response->assertStatus(404);
    }

    public function testShowFailsForNonExistentUser()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('tenant.settings.site-users.dealerships.show', 999999));

        $response->assertStatus(404);
    }

    public function testUpdateSyncsDealerships()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $dealership1 = Dealership::factory()->create();
        $dealership2 = Dealership::factory()->create();
        $dealership3 = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), [
                'dealership_ids' => [$dealership1->id, $dealership3->id],
            ]);

        $response->assertStatus(200);
        $response->assertJson([
            'message' => 'User dealership access updated successfully.',
        ]);

        $assignedIds = DB::table('user_dealerships')
            ->where('user_id', $targetUser->id)
            ->pluck('dealership_id')
            ->toArray();

        $this->assertCount(2, $assignedIds);
        $this->assertContains($dealership1->id, $assignedIds);
        $this->assertContains($dealership3->id, $assignedIds);
        $this->assertNotContains($dealership2->id, $assignedIds);
    }

    public function testUpdateReplacesExistingAssignments()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $dealership1 = Dealership::factory()->create();
        $dealership2 = Dealership::factory()->create();
        $dealership3 = Dealership::factory()->create();

        // Pre-assign dealership 1 and 2
        DB::table('user_dealerships')->insert([
            ['user_id' => $targetUser->id, 'dealership_id' => $dealership1->id],
            ['user_id' => $targetUser->id, 'dealership_id' => $dealership2->id],
        ]);

        // Sync to only dealership 3
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), [
                'dealership_ids' => [$dealership3->id],
            ]);

        $response->assertStatus(200);

        $assignedIds = DB::table('user_dealerships')
            ->where('user_id', $targetUser->id)
            ->pluck('dealership_id')
            ->toArray();

        $this->assertCount(1, $assignedIds);
        $this->assertContains($dealership3->id, $assignedIds);
        $this->assertNotContains($dealership1->id, $assignedIds);
        $this->assertNotContains($dealership2->id, $assignedIds);
    }

    public function testUpdateRemovesAllDealershipsWhenEmptyArrayProvided()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $dealership = Dealership::factory()->create();

        DB::table('user_dealerships')->insert([
            'user_id' => $targetUser->id,
            'dealership_id' => $dealership->id,
        ]);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), [
                'dealership_ids' => [],
            ]);

        $response->assertStatus(200);

        $count = DB::table('user_dealerships')
            ->where('user_id', $targetUser->id)
            ->count();

        $this->assertEquals(0, $count);
    }

    public function testUpdateFailsForUserNotOnTenant()
    {
        $targetUser = User::factory()->create();

        $dealership = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), [
                'dealership_ids' => [$dealership->id],
            ]);

        $response->assertStatus(404);
    }

    public function testUpdateFailsForNonExistentUser()
    {
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', 999999), [
                'dealership_ids' => [],
            ]);

        $response->assertStatus(404);
    }

    public function testUpdateValidatesDealershipIdsIsRequired()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), []);

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

    public function testUpdateValidatesDealershipIdsMustBeArray()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), [
                'dealership_ids' => 'not-an-array',
            ]);

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

    public function testUpdateValidatesDealershipIdsMustExist()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), [
                'dealership_ids' => [999999],
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['dealership_ids.0']);
    }

    public function testUpdateDoesNotAffectOtherUsersAssignments()
    {
        $targetUser = User::factory()->create();
        $targetUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $otherUser = User::factory()->create();
        $otherUser->tenants()->attach(tenant('id'), ['role' => 'Editor']);

        $dealership1 = Dealership::factory()->create();
        $dealership2 = Dealership::factory()->create();

        // Assign both users to dealership 1
        DB::table('user_dealerships')->insert([
            ['user_id' => $targetUser->id, 'dealership_id' => $dealership1->id],
            ['user_id' => $otherUser->id, 'dealership_id' => $dealership1->id],
        ]);

        // Update only target user to dealership 2
        $response = $this->actingAs($this->getUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->putJson(route('tenant.settings.site-users.dealerships.update', $targetUser->id), [
                'dealership_ids' => [$dealership2->id],
            ]);

        $response->assertStatus(200);

        // Target user should only have dealership 2
        $targetIds = DB::table('user_dealerships')
            ->where('user_id', $targetUser->id)
            ->pluck('dealership_id')
            ->toArray();
        $this->assertEquals([$dealership2->id], $targetIds);

        // Other user should still have dealership 1
        $otherIds = DB::table('user_dealerships')
            ->where('user_id', $otherUser->id)
            ->pluck('dealership_id')
            ->toArray();
        $this->assertEquals([$dealership1->id], $otherIds);
    }
}
