<?php

use App\Models\Customer;
use App\Models\Operator;
use App\Models\User;

it('shows the signup page to guests', function () {
    $this->get(route('register'))->assertOk()->assertSee(__('auth.register_title'));
});

it('links between login and signup', function () {
    $this->get(route('login'))->assertOk()->assertSee(route('register'));
    $this->get(route('register'))->assertOk()->assertSee(route('login'));
});

it('registers a new account and signs in', function () {
    $this->post(route('register.store'), [
        'name' => 'New Co',
        'email' => 'new@signup.test',
        'customer_type' => Customer::TYPE_BUSINESS,
        'password' => 'password1234',
        'password_confirmation' => 'password1234',
    ])->assertRedirect();

    $user = User::query()->where('email', 'new@signup.test')->first();
    // A registered user is never an operator: the two no longer share a table
    // or a role system to check "isOperator" against at all.
    expect($user)->not->toBeNull();
    $this->assertAuthenticatedAs($user);

    // A linked customer is created so the portal has something to work with.
    $customer = Customer::query()->where('user_id', $user->id)->first();
    expect($customer)->not->toBeNull()
        ->and($customer->email)->toBe('new@signup.test')
        // The answer they gave, stored as given. Everything downstream — the
        // withdrawal right, the invoice wording, reverse charge — reads this
        // and not the VAT field.
        ->and($customer->customer_type)->toBe(Customer::TYPE_BUSINESS)
        ->and($customer->isBusiness())->toBeTrue();
});

it('refuses a signup that does not say whether it is a consumer or a business', function () {
    // Required rather than optional-with-a-default. A default would be an
    // answer nobody gave, and the whole point of the column is that it holds a
    // recorded answer or nothing at all.
    $this->post(route('register.store'), [
        'name' => 'Unanswered',
        'email' => 'unanswered@signup.test',
        'password' => 'password1234',
        'password_confirmation' => 'password1234',
    ])->assertSessionHasErrors('customer_type');

    expect(User::query()->where('email', 'unanswered@signup.test')->exists())->toBeFalse();
});

it('refuses a customer type that is neither of the two answers', function () {
    $this->post(route('register.store'), [
        'name' => 'Sneaky',
        'email' => 'sneaky@signup.test',
        'customer_type' => 'charity',
        'password' => 'password1234',
        'password_confirmation' => 'password1234',
    ])->assertSessionHasErrors('customer_type');

    expect(Customer::query()->where('email', 'sneaky@signup.test')->exists())->toBeFalse();
});

it('refuses to register with an existing customer email (account-claim guard)', function () {
    Customer::factory()->create(['email' => 'claim@signup.test']);

    $this->post(route('register.store'), [
        'name' => 'Claimer', 'email' => 'claim@signup.test',
        'password' => 'password1234', 'password_confirmation' => 'password1234',
    ])->assertSessionHasErrors('email');

    expect(User::query()->where('email', 'claim@signup.test')->exists())->toBeFalse();
});

it('refuses to register with an existing operator email', function () {
    // R21: the operator side of the same account-claim guard above — an
    // address that already belongs to staff must not become a customer too.
    Operator::factory()->create(['email' => 'staff@signup.test']);

    $this->post(route('register.store'), [
        'name' => 'Claimer', 'email' => 'staff@signup.test',
        'password' => 'password1234', 'password_confirmation' => 'password1234',
    ])->assertSessionHasErrors('email');

    expect(User::query()->where('email', 'staff@signup.test')->exists())->toBeFalse();
});

it('throttles repeated registration attempts', function () {
    $hit429 = false;
    for ($i = 0; $i < 24; $i++) {
        $res = $this->post(route('register.store'), [
            'name' => 'S', 'email' => "spam{$i}@signup.test",
            'password' => 'password1234', 'password_confirmation' => 'password1234',
        ]);
        if ($res->status() === 429) {
            $hit429 = true;
            break;
        }
    }
    expect($hit429)->toBeTrue();
});

it('rejects a mismatched password confirmation', function () {
    $this->post(route('register.store'), [
        'name' => 'X',
        'email' => 'x@signup.test',
        'password' => 'password1234',
        'password_confirmation' => 'different',
    ])->assertSessionHasErrors('password');

    expect(User::query()->where('email', 'x@signup.test')->exists())->toBeFalse();
});
