<?php

namespace App\Livewire\Attendance;

use App\Domain\Attendance\Services\SelfCheckInService;
use App\Domain\Shared\Context\BranchContext;
use App\Domain\Shared\Exceptions\DomainException;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

/**
 * The gate: staff scan the member's rotating pass and attendance is marked.
 *
 * Staff-scan only. The other direction — a printed poster the member scans — was
 * cut on purpose: a printed QR is a public, permanent, non-secret string, so
 * rotation is impossible by construction. It proves the member once visited, or
 * knows someone who did, not that they are present. Only a powered display
 * running a rotating code produces real evidence, and paper cannot.
 *
 * Rate limits are per staff member and per participant, because the two abuses
 * are different: a broken scanner hammering the endpoint, and someone walking a
 * queue of screenshots past it.
 */
#[Layout('layouts.app')]
#[Title('مسح بطاقة الحضور')]
class CheckInScanner extends Component
{
    public string $token = '';

    /** @var array<int, array{name: string, session: string, at: string, replay: bool}> */
    public array $recent = [];

    public ?string $error = null;

    public ?string $success = null;

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

    public function scan(SelfCheckInService $checkIn): void
    {
        $this->authorize('attendance.scan');

        $this->error = null;
        $this->success = null;

        $token = trim($this->token);
        $this->token = '';

        if ($token === '') {
            return;
        }

        $user = auth()->user();

        // 60 scans a minute is a busy gate; more than that is a stuck scanner.
        $staffKey = "checkin-scan:staff:{$user->id}";

        if (\Illuminate\Support\Facades\RateLimiter::tooManyAttempts($staffKey, 60)) {
            $this->error = __('عدد كبير من المحاولات — انتظر قليلاً');

            return;
        }

        \Illuminate\Support\Facades\RateLimiter::hit($staffKey, 60);

        try {
            $result = $checkIn->scan(
                $token,
                $user,
                app(BranchContext::class)->branchId(),
                request()->ip(),
            );
        } catch (DomainException $e) {
            $this->error = $e->getMessage();

            return;
        }

        $name = $result['participant']->person?->name_ar ?? $result['participant']->person?->name ?? '—';
        $session = $result['session']->group?->name_ar ?? __('حصة');

        $this->success = $result['replay']
            ? __('تم تسجيل الحضور مسبقاً') . ' — ' . $name
            : __('تم تسجيل الحضور') . ' — ' . $name;

        array_unshift($this->recent, [
            'name' => $name,
            'session' => $session,
            'at' => now()->format('H:i:s'),
            'replay' => $result['replay'],
        ]);

        $this->recent = array_slice($this->recent, 0, 12);
    }

    public function render()
    {
        return view('livewire.attendance.check-in-scanner');
    }
}
