<div class="mx-auto max-w-2xl space-y-5"
     x-data="scanner()" x-init="init()">

    <header>
        <h1 class="text-xl font-bold text-gray-900">{{ __('مسح بطاقة الحضور') }}</h1>
        <p class="mt-0.5 text-sm text-gray-500">
            {{ __('وجّه الكاميرا إلى رمز :member، أو استخدم قارئ الباركود المتصل.', ['member' => term('member_definite')]) }}
        </p>
    </header>

    {{-- The camera is progressive enhancement. A USB barcode reader types into
         the focused field and works with no camera permission at all, which is
         what most reception desks actually have. --}}
    <div class="overflow-hidden rounded-xl border border-gray-200 bg-black" x-show="cameraOn" x-cloak>
        <video x-ref="video" class="aspect-video w-full object-cover" muted playsinline></video>
    </div>

    <div class="rounded-xl border border-gray-200 bg-white p-4 sm:p-5">
        <form wire:submit="scan" class="flex gap-2">
            <input type="text" wire:model="token" x-ref="input" dir="ltr" autocomplete="off"
                   placeholder="{{ __('امسح الرمز أو الصقه هنا') }}"
                   class="flex-1 rounded-lg border-gray-300 font-mono text-sm">
            <button type="submit" wire:loading.attr="disabled" wire:target="scan"
                    class="rounded-lg bg-blue-600 px-5 py-2 text-sm font-bold text-white hover:bg-blue-700 disabled:opacity-60">
                <span wire:loading.remove wire:target="scan">{{ __('تسجيل') }}</span>
                <span wire:loading wire:target="scan">{{ __('...') }}</span>
            </button>
        </form>

        <div class="mt-3 flex items-center gap-3">
            <button type="button" @click="toggleCamera()" x-show="cameraSupported"
                    class="rounded-lg border border-gray-300 px-3 py-1.5 text-xs font-semibold text-gray-700 hover:bg-gray-50">
                <span x-show="!cameraOn">{{ __('تشغيل الكاميرا') }}</span>
                <span x-show="cameraOn" x-cloak>{{ __('إيقاف الكاميرا') }}</span>
            </button>
            <span x-show="!cameraSupported" class="text-xs text-gray-500">
                {{ __('هذا المتصفح لا يدعم قراءة الرمز بالكاميرا — استخدم قارئاً متصلاً.') }}
            </span>
        </div>

        @if($error)
            <p class="mt-4 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm font-medium text-red-700">
                {{ $error }}
            </p>
        @endif

        @if($success)
            <p class="mt-4 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm font-medium text-emerald-700">
                {{ $success }}
            </p>
        @endif
    </div>

    @if(count($recent) > 0)
        <section class="overflow-hidden rounded-xl border border-gray-200 bg-white">
            <h2 class="border-b border-gray-100 px-4 py-3 text-sm font-bold text-gray-900">{{ __('آخر عمليات المسح') }}</h2>
            <ul class="divide-y divide-gray-100">
                @foreach($recent as $entry)
                    <li class="flex items-center justify-between gap-3 px-4 py-2.5 text-sm">
                        <span class="font-medium text-gray-900">{{ $entry['name'] }}</span>
                        <span class="text-xs text-gray-500">{{ $entry['session'] }}</span>
                        <span class="font-mono text-xs text-gray-400" dir="ltr">{{ $entry['at'] }}</span>
                        @if($entry['replay'])
                            <span class="rounded-full bg-gray-100 px-2 py-0.5 text-[10px] font-bold text-gray-600">
                                {{ __('مكرر') }}
                            </span>
                        @endif
                    </li>
                @endforeach
            </ul>
        </section>
    @endif
</div>

@script
<script>
Alpine.data('scanner', () => ({
    cameraOn: false,
    cameraSupported: false,
    stream: null,
    detector: null,
    timer: null,

    init() {
        // BarcodeDetector is not everywhere. Where it is missing the desk uses
        // a connected reader, which types into the focused field.
        this.cameraSupported = 'BarcodeDetector' in window && !!navigator.mediaDevices;
        this.$refs.input?.focus();

        // Keep focus on the field: a barcode reader is a keyboard, and a lost
        // focus means the scan lands nowhere.
        document.addEventListener('click', () => this.$refs.input?.focus());
    },

    async toggleCamera() {
        this.cameraOn ? this.stopCamera() : await this.startCamera();
    },

    async startCamera() {
        try {
            this.detector = new BarcodeDetector({ formats: ['qr_code'] });
            this.stream = await navigator.mediaDevices.getUserMedia({
                video: { facingMode: 'environment' },
            });
            this.$refs.video.srcObject = this.stream;
            await this.$refs.video.play();
            this.cameraOn = true;
            this.loop();
        } catch (error) {
            this.cameraSupported = false;
        }
    },

    stopCamera() {
        clearTimeout(this.timer);
        this.stream?.getTracks().forEach((track) => track.stop());
        this.stream = null;
        this.cameraOn = false;
    },

    loop() {
        if (!this.cameraOn) return;

        this.detector.detect(this.$refs.video)
            .then((codes) => {
                if (codes.length > 0) {
                    // Straight to the server. The token is never held in a
                    // variable longer than this call and never put in a URL.
                    this.$wire.set('token', codes[0].rawValue, false);
                    this.$wire.scan();
                }
            })
            .catch(() => {})
            .finally(() => {
                this.timer = setTimeout(() => this.loop(), 350);
            });
    },
}));
</script>
@endscript
