<?php

namespace Tests\Feature;

use App\Models\AdminUser;
use App\Models\Customer;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Laravel\Socialite\Contracts\User as SocialiteUser;
use Laravel\Socialite\Facades\Socialite;
use Mockery;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Tests\TestCase;

class CustomerGoogleLoginTest extends TestCase
{
    use RefreshDatabase;

    public function test_customer_can_redirect_to_google(): void
    {
        $provider = Mockery::mock();
        $provider->shouldReceive('stateless')->once()->andReturnSelf();
        $provider->shouldReceive('redirect')->once()->andReturn(new RedirectResponse('https://accounts.google.com/o/oauth2/auth'));

        Socialite::shouldReceive('driver')
            ->once()
            ->with('google')
            ->andReturn($provider);

        $this->get('/auth/google')
            ->assertRedirect('https://accounts.google.com/o/oauth2/auth');
    }

    public function test_google_callback_creates_customer_and_logs_in_customer_guard(): void
    {
        $this->mockGoogleUser(
            id: 'google-123',
            name: 'Google Customer',
            email: 'google.customer@example.com',
            avatar: 'https://example.com/avatar.jpg'
        );

        $this->get('/auth/google/callback')
            ->assertRedirect(route('customer.account'));

        $this->assertAuthenticated('customer');
        $this->assertGuest('admin');
        $this->assertDatabaseHas('customers', [
            'email' => 'google.customer@example.com',
            'google_id' => 'google-123',
            'avatar' => 'https://example.com/avatar.jpg',
        ]);
        $this->assertDatabaseMissing('admin_users', [
            'email' => 'google.customer@example.com',
        ]);
    }

    public function test_google_callback_links_existing_customer_by_email(): void
    {
        Customer::query()->create([
            'name' => 'Existing Customer',
            'email' => 'existing.google@example.com',
            'password' => Hash::make('secret-password'),
        ]);

        $this->mockGoogleUser(
            id: 'google-existing-123',
            name: 'Existing Google Customer',
            email: 'existing.google@example.com',
            avatar: 'https://example.com/existing.jpg'
        );

        $this->get('/auth/google/callback')
            ->assertRedirect(route('customer.account'));

        $this->assertSame(1, Customer::query()->where('email', 'existing.google@example.com')->count());
        $this->assertDatabaseHas('customers', [
            'email' => 'existing.google@example.com',
            'google_id' => 'google-existing-123',
        ]);
    }

    public function test_admin_user_is_not_authenticated_or_created_by_customer_google_login(): void
    {
        AdminUser::query()->create([
            'name' => 'Admin',
            'email' => 'admin.google@example.com',
            'password' => Hash::make('secret-password'),
            'is_active' => true,
        ]);

        $this->mockGoogleUser(
            id: 'google-admin-email',
            name: 'Admin Email Customer',
            email: 'admin.google@example.com',
            avatar: null
        );

        $this->get('/auth/google/callback')
            ->assertRedirect(route('customer.account'));

        $this->assertAuthenticated('customer');
        $this->assertGuest('admin');
        $this->assertSame(1, AdminUser::query()->where('email', 'admin.google@example.com')->count());
        $this->assertDatabaseHas('customers', [
            'email' => 'admin.google@example.com',
            'google_id' => 'google-admin-email',
        ]);
    }

    private function mockGoogleUser(string $id, string $name, string $email, ?string $avatar): void
    {
        $socialiteUser = Mockery::mock(SocialiteUser::class);
        $socialiteUser->shouldReceive('getId')->andReturn($id);
        $socialiteUser->shouldReceive('getName')->andReturn($name);
        $socialiteUser->shouldReceive('getNickname')->andReturn(null);
        $socialiteUser->shouldReceive('getEmail')->andReturn($email);
        $socialiteUser->shouldReceive('getAvatar')->andReturn($avatar);

        $provider = Mockery::mock();
        $provider->shouldReceive('stateless')->once()->andReturnSelf();
        $provider->shouldReceive('user')->once()->andReturn($socialiteUser);

        Socialite::shouldReceive('driver')
            ->once()
            ->with('google')
            ->andReturn($provider);
    }
}
