<?php

use App\Models\Group;
use App\Models\User;
use Laravel\Socialite\Contracts\Provider;
use Laravel\Socialite\Facades\Socialite;

use function Pest\Laravel\get;

beforeEach(function () {
    Group::firstOrCreate(['name' => Group::ADMIN]);
    Group::firstOrCreate(['name' => Group::MEMBERS]);
});

function fakeGoogleUser(string $email, string $googleId = 'google-123', ?string $name = 'Google User'): Provider
{
    $provider = Mockery::mock(Provider::class);
    $user = Mockery::mock();
    $user->shouldReceive('getId')->andReturn($googleId);
    $user->shouldReceive('getEmail')->andReturn($email);
    $user->shouldReceive('getName')->andReturn($name);
    $user->shouldReceive('getNickname')->andReturn(null);
    $user->shouldReceive('getAvatar')->andReturn(null);

    $provider->shouldReceive('redirect')->andReturn(redirect('https://accounts.google.com'));
    $provider->shouldReceive('user')->andReturn($user);

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

    return $provider;
}

test('new google user is created with members group and logged in', function () {
    fakeGoogleUser('new@gmail.com');

    $response = get(route('auth.google.callback'));

    $response->assertRedirect(route('dashboard'));
    $this->assertAuthenticated();

    $user = User::where('email', 'new@gmail.com')->first();
    expect($user)->not->toBeNull()
        ->and($user->google_id)->toBe('google-123')
        ->and($user->groupNames()->contains(Group::MEMBERS))->toBeTrue()
        ->and($user->email_verified_at)->not->toBeNull();
});

test('existing user by email gets google_id linked and logged in', function () {
    $existing = User::factory()->create(['email' => 'existing@gmail.com', 'google_id' => null]);

    fakeGoogleUser('existing@gmail.com', 'g-999');

    get(route('auth.google.callback'))->assertRedirect(route('dashboard'));

    $this->assertAuthenticated();
    expect(User::where('email', 'existing@gmail.com')->count())->toBe(1);
    expect($existing->fresh()->google_id)->toBe('g-999');
});

test('existing user by google_id is logged in without duplicate', function () {
    $user = User::factory()->create(['email' => 'returning@gmail.com', 'google_id' => 'g-return']);

    fakeGoogleUser('returning@gmail.com', 'g-return');

    get(route('auth.google.callback'))->assertRedirect(route('dashboard'));

    $this->assertAuthenticatedAs($user);
    expect(User::where('google_id', 'g-return')->count())->toBe(1);
});

test('inactive user cannot login via google', function () {
    User::factory()->create(['email' => 'banned@gmail.com', 'google_id' => 'g-ban', 'status' => 'suspended']);

    fakeGoogleUser('banned@gmail.com', 'g-ban');

    get(route('auth.google.callback'))
        ->assertRedirect(route('login'))
        ->assertSessionHas('error');

    $this->assertGuest();
});

test('google redirect goes to google', function () {
    fakeGoogleUser('any@gmail.com');

    $response = get(route('auth.google.redirect'));

    $response->assertRedirect('https://accounts.google.com');
});
