<?php

use App\Models\Customer;
use App\Models\Subscription;
use App\Models\User;
use App\Services\Billing\SetupFee;
use App\Support\Settings;
use Illuminate\Support\Facades\File;

/**
 * The order, before it is placed.
 *
 * There was no such page. The order page posted straight to Stripe: the last
 * thing a customer saw in this product's design was a grid of packages, and the
 * next was somebody else's card form. What they were buying, what it costs in
 * total, what happens afterwards and what they were agreeing to were never
 * stated in one place — and the terms box sat at the TOP of the package list,
 * as a condition of looking at prices.
 */
function checkoutUser(): User
{
    return User::factory()->create(['email_verified_at' => now()]);
}

it('states the package, the term and every figure that will be charged', function () {
    $page = $this->actingAs(checkoutUser())
        ->get(route('checkout', ['plan' => 'team', 'term' => 'monthly']))
        ->assertOk();

    $page->assertSee('Team')
        ->assertSee(__('order.term_monthly'))
        // Net, tax and gross: 79,00 net, 20 % VAT, 94,80 to pay.
        ->assertSee('79,00')
        ->assertSee('94,80')
        ->assertSee(__('checkout.total_today'))
        // And what comes after the first charge, which is not the same figure
        // whenever a setup fee is on the first one. Asserted in two pieces: the
        // formatter puts a non-breaking space before the sign, and building the
        // expected string by hand is a test that checks its own typing.
        ->assertSee(mb_substr(__('checkout.then_monthly', ['amount' => '']), 0, 6));
});

it('adds the setup fee to what is due today and to nothing after it', function () {
    Settings::set('company.setup_fee_cents', 9900);

    $page = $this->actingAs(checkoutUser())
        ->get(route('checkout', ['plan' => 'team', 'term' => 'monthly']))
        ->assertOk();

    // 94,80 for the month plus 118,80 for the setup — both gross.
    $page->assertSee(__('checkout.setup_line'))
        // 94,80 for the month plus 118,80 for the setup.
        ->assertSee('213,60')
        // The recurring figure alone is what follows the first charge.
        ->assertSee('94,80');

    expect(SetupFee::netCents())->toBe(9900);
});

it('refuses to place the order without the terms, whatever the browser did', function () {
    // The button is disabled until the box is ticked, and disabling a button in
    // a browser refuses nothing. This is the rule.
    $this->actingAs(checkoutUser())
        ->post(route('checkout.start'), ['plan' => 'team', 'term' => 'monthly'])
        ->assertSessionHasErrors('terms_accepted');
});

it('puts the acceptance under the total and over the button', function () {
    // The order it is read in: what you get, what it costs, what you agree to,
    // then the button. It used to be first, above the prices.
    $page = File::get(resource_path('views/livewire/checkout.blade.php'));

    expect(strpos($page, "__('checkout.total_today')"))
        ->toBeLessThan(strpos($page, "__('order.terms_label'"))
        ->and(strpos($page, "__('order.terms_label'"))
        ->toBeLessThan(strpos($page, "__('checkout.pay_cta')"));
});

it('says what happens after the button, because the next screen is a stranger', function () {
    // Being handed to a payment provider is the moment a first-time buyer wants
    // to know what they are getting into.
    $this->actingAs(checkoutUser())
        ->get(route('checkout', ['plan' => 'start']))
        ->assertOk()
        ->assertSee(__('checkout.step_pay_title'))
        ->assertSee(__('checkout.step_build_title'))
        ->assertSee(__('checkout.step_credentials_title'))
        ->assertSee(__('checkout.stripe_note'));
});

it('answers a package nobody sells with a sentence, not a stack trace', function () {
    // Reached from a retyped address, or from a package taken off sale between
    // the two pages.
    $this->actingAs(checkoutUser())
        ->get(route('checkout', ['plan' => 'gibt-es-nicht']))
        ->assertOk()
        ->assertSee(__('checkout.unknown_plan'));
});

it('sends a customer who already has a contract to their billing page', function () {
    // A second checkout would build a second, empty cloud and bill for both.
    // The order page says so; a link straight into this page skips that.
    $user = checkoutUser();
    $customer = Customer::factory()->create(['email' => $user->email, 'user_id' => $user->id]);
    Subscription::factory()->create(['customer_id' => $customer->id, 'status' => 'active']);

    $this->actingAs($user)
        ->get(route('checkout', ['plan' => 'team']))
        ->assertOk()
        ->assertSee(__('order.already_customer'))
        ->assertDontSee(__('checkout.pay_cta'));
});

it('is behind the same door as everything else', function () {
    // An unconfirmed address is not a billing detail to be caught at checkout:
    // the finished cloud's credentials are sent to it.
    $this->get(route('checkout', ['plan' => 'team']))->assertRedirect();

    $this->actingAs(User::factory()->unverified()->create())
        ->get(route('checkout', ['plan' => 'team']))
        ->assertRedirect(route('verification.notice'));
});

// ---- The mark in the mails ----

it('draws the mark in the mail header, not an empty orange tile', function () {
    // It shipped as a plain square: the ascent inside the mark lives in an SVG
    // the site loads, and a mail cannot — Gmail strips inline SVG, Outlook
    // renders with Word, and this layout carries no image by design. So the
    // shape is a character every mail font has.
    $html = (string) app(App\Services\Mail\MailPreviews::class)->make('verify-email')?->render();

    // As the entity it is written with: a mail is markup, and &#9650; is what
    // survives every client's encoding guesswork.
    expect($html)->toContain('&#9650;')
        ->and($html)->toContain('#f97316')
        // And the whole name beside it, as the wordmark writes it.
        ->and($html)->toContain('CluPilot')
        ->and($html)->toContain('Cloud');
});
