<?php

namespace App\Livewire\Portal;

use App\Domain\Identity\Models\Person;
use App\Domain\Identity\Models\PortalInvitation;
use App\Domain\Identity\Services\PortalInvitationService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\WhatsApp\Services\WhatsAppService;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

/**
 * Staff issue portal invitations from here.
 *
 * The raw token exists exactly once, in the response to the click that created
 * it — after that only its SHA-256 is stored and nobody, staff included, can
 * recover the link. Re-inviting revokes the previous one rather than leaving
 * two working links in the wild.
 */
#[Layout('layouts.app')]
#[Title('دعوات بوابة الأعضاء')]
class PortalInvitationManager extends Component
{
    use WithPagination;

    #[Url(as: 'q')]
    public string $search = '';

    /**
     * The one moment the raw link exists. Held for this render only and never
     * written anywhere; a refresh loses it, which is the correct behaviour for
     * a single-use credential.
     */
    public ?string $freshLink = null;

    #[Locked]
    public ?int $freshPersonId = null;

    public function mount(): void
    {
        $this->authorize('users.create');
    }

    public function updatedSearch(): void
    {
        $this->resetPage();
    }

    public function invite(int $personId, PortalInvitationService $invitations): void
    {
        $this->authorize('users.create');

        $person = Person::findOrFail($personId);

        try {
            ['invitation' => $invitation, 'token' => $token] = $invitations->issue(
                $person,
                auth()->user(),
                null,
                'link',
                request()->ip(),
            );
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());

            return;
        }

        $this->freshLink = route('portal.activate', $token);
        $this->freshPersonId = $person->id;

        session()->flash('success', __('تم إنشاء رابط التفعيل — انسخه الآن، لن يظهر مرة أخرى'));
    }

    public function sendViaWhatsApp(int $personId, PortalInvitationService $invitations, WhatsAppService $whatsapp): void
    {
        $this->authorize('users.create');

        $person = Person::findOrFail($personId);

        if (! $person->phone) {
            session()->flash('error', __('لا يوجد رقم هاتف لهذا الشخص'));

            return;
        }

        try {
            ['token' => $token] = $invitations->issue($person, auth()->user(), null, 'whatsapp', request()->ip());
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());

            return;
        }

        $link = route('portal.activate', $token);
        $academy = app('current_academy');

        $whatsapp->sendText(
            $person->phone,
            __('مرحباً') . ' ' . ($person->name_ar ?: $person->name) . "\n\n"
            . __('فعّل حسابك في بوابة') . ' ' . ($academy->name_ar ?: $academy->name) . ":\n"
            . $link . "\n\n"
            . __('الرابط صالح لمدة ٧٢ ساعة ويُستخدم مرة واحدة.')
        );

        session()->flash('success', __('أُرسل الرابط عبر واتساب'));
    }

    public function revoke(int $invitationId, PortalInvitationService $invitations): void
    {
        $this->authorize('users.create');

        $invitations->revoke(PortalInvitation::findOrFail($invitationId));

        session()->flash('success', __('تم إلغاء الدعوة'));
    }

    public function render()
    {
        $people = Person::query()
            ->when($this->search !== '', function ($q) {
                $term = '%' . $this->search . '%';
                // The closure keeps both branches inside the tenant scope.
                $q->where(function ($inner) use ($term) {
                    $inner->where('name_ar', 'like', $term)
                        ->orWhere('name', 'like', $term)
                        ->orWhere('phone', 'like', $term);
                });
            })
            ->whereHas('guardian')
            ->orderBy('name_ar')
            ->paginate(15);

        $invitations = PortalInvitation::with(['person', 'creator'])
            ->orderByDesc('created_at')
            ->limit(20)
            ->get();

        return view('livewire.portal.portal-invitation-manager', [
            'people' => $people,
            'invitations' => $invitations,
            'activeByPerson' => $invitations->whereNull('consumed_at')->whereNull('revoked_at')
                ->where('expires_at', '>', now())->keyBy('person_id'),
        ]);
    }
}
