<?php

namespace App\Livewire\Admin;

use App\Actions\WithdrawContract;
use App\Models\Customer;
use App\Models\Subscription;
use App\Services\Billing\CustomDomainAccess;
use App\Services\Billing\WithdrawalRight;
use LivewireUI\Modal\ModalComponent;
use RuntimeException;

/**
 * A withdrawal that arrived by telephone or by post, typed in by an operator.
 *
 * The law does not require a consumer to use our form. A sentence on the phone,
 * a letter, an email — any unambiguous declaration inside the fourteen days
 * ends the contract, and if the only way to record one were the portal button,
 * the ones that came in every other way would be handled by hand in Stripe and
 * never appear in the register at all.
 *
 * So it goes through the SAME action as the portal, with the channel recorded
 * and the operator's name on it. Nothing is decided here that is not decided
 * there: a business customer is refused, an expired window is refused, and the
 * refund is the whole amount either way. An operator cannot override any of it,
 * which is the point — a withdrawal an operator could approve out of the window
 * would be a refund with no legal basis and no document that could justify it.
 *
 * `customers.manage` rather than `customers.grant_plan`: this is not a gift an
 * operator decides to make, it is a declaration the customer has already made
 * and somebody is writing down. Support answers the telephone, and Support holds
 * `customers.manage`.
 */
class RecordWithdrawal extends ModalComponent
{
    public string $customerUuid = '';

    public string $customerName = '';

    /** Why it cannot be recorded, in the customer's own words. Null when it can. */
    public ?string $refusal = null;

    public function mount(string $uuid): void
    {
        // Modals are reachable without the route middleware, so the permission
        // is checked here as well as on the page that opens this one.
        $this->authorize('customers.manage');

        $customer = Customer::query()->where('uuid', $uuid)->firstOrFail();

        $this->customerUuid = $uuid;
        $this->customerName = (string) $customer->name;
        $this->refusal = WithdrawalRight::for($this->contractOf($customer))->refusal;
    }

    public function record(): void
    {
        $this->authorize('customers.manage');

        $customer = Customer::query()->where('uuid', $this->customerUuid)->firstOrFail();
        $contract = $this->contractOf($customer);

        if ($contract === null) {
            $this->refusal = __('withdrawal.refusal_no_contract');

            return;
        }

        try {
            app(WithdrawContract::class)(
                $contract,
                WithdrawContract::CHANNEL_OPERATOR,
                // Who took it. Part of the evidence that a declaration was made
                // at all — a refund with nobody's name against it is the one an
                // auditor asks about.
                auth('operator')->user(),
            );
        } catch (RuntimeException $e) {
            $this->refusal = $e->getMessage();

            return;
        }

        $this->dispatch('notify', message: __('withdrawal.recorded', ['name' => $this->customerName]));
        $this->closeModal();
    }

    private function contractOf(Customer $customer): ?Subscription
    {
        return app(CustomDomainAccess::class)->contractOf($customer);
    }

    public function render()
    {
        $customer = Customer::query()->where('uuid', $this->customerUuid)->first();
        $contract = $customer === null ? null : $this->contractOf($customer);

        return view('livewire.admin.record-withdrawal', [
            'right' => WithdrawalRight::for($contract),
            // How long the cloud has been running. Nothing is charged for it —
            // the refund is the whole amount — but it is the first thing an
            // operator is asked on the telephone.
            'deliveredDays' => $contract === null ? 0 : WithdrawalRight::deliveredDays($contract),
            'termDays' => $contract === null ? 0 : WithdrawalRight::termDays($contract),
        ]);
    }
}
