{{--
    The Quick PIN pad's Alpine component, registered by name so the login
    page's wrapper only ever carries `x-data="quickPinLogin"`.

    This deliberately does NOT live inline in an `x-data` attribute. Filament
    writes extra attributes with `escape: false`, and Laravel's
    ComponentAttributeBag::__toString() escapes a `"` as `\"` — JS escaping, not
    HTML. A double quote anywhere in the expression therefore terminates the
    attribute early, the browser hands Alpine a truncated (invalid) expression,
    Alpine falls back to an empty scope, and every `x-show` inside the wrapper
    resolves to undefined — silently hiding the PIN pad AND the password form,
    leaving a login card with nothing in it. Keeping the JS in a <script> keeps
    normal quoting rules and removes that whole failure mode.

    Registered against `alpine:init` (this script is inside the page slot, which
    Filament renders before `@filamentScripts`, so the listener is always in
    place before Alpine boots) — with a direct fallback for the case where
    Alpine is already running, e.g. a `wire:navigate` visit where `alpine:init`
    has already fired.
--}}
<script>
    (function () {
        const quickPinLogin = () => ({
            device: (() => {
                try {
                    return JSON.parse(localStorage.getItem('quickPinDevice') || 'null');
                } catch (e) {
                    return null;
                }
            })(),
            pinCan: false,
            pinPad: false,
            pin: '',
            error: null,
            submitting: false,

            init() {
                // Only offer the pad when the stored device belongs to a user who
                // actually has a PIN — the server mints these tokens exclusively
                // for such accounts (and clears stale ones), this is just a
                // client-side guard for tokens minted before that rule existed.
                this.pinCan = !! (this.device && this.device.user && this.device.user.has_pin);
                this.pinPad = this.pinCan;
            },

            clearDevice() {
                localStorage.removeItem('quickPinDevice');
                this.device = null;
                this.pinCan = false;
                this.pinPad = false;
            },

            async submitPin() {
                this.submitting = true;
                this.error = null;

                try {
                    const res = await fetch(@js(route('pin-login')), {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Accept': 'application/json',
                            'X-CSRF-TOKEN': @js(csrf_token()),
                        },
                        body: JSON.stringify({ device_token: this.device.token, pin: this.pin }),
                    });

                    const data = await res.json();

                    if (! res.ok) {
                        // A wrong PIN and an untrusted/expired device return the
                        // identical code by design — the frontend can't (and
                        // shouldn't) tell them apart, so both fall back to password.
                        if (data.code === 'device_untrusted') {
                            this.clearDevice();
                        } else {
                            this.error = data.message ?? 'Something went wrong. Please try again.';
                        }

                        this.pin = '';

                        return;
                    }

                    window.location.href = data.redirect;
                } catch (e) {
                    this.error = 'Something went wrong. Please try again.';
                    this.pin = '';
                } finally {
                    this.submitting = false;
                }
            },
        });

        // Belt and braces, because the cost of `x-data="quickPinLogin"` failing
        // to resolve is a login card with no form in it.
        //
        // `Alpine.data()` is the idiomatic registration, but it only counts if
        // it lands before Alpine walks the DOM. Publishing the same factory as
        // a global removes that ordering dependency altogether: an identifier
        // Alpine can't find in scope falls through to `window`, and Alpine
        // auto-calls a function an expression resolves to — so `x-data` gets
        // the same object either way. When both are in place the registered
        // provider shadows the global, so this changes nothing in the happy
        // path.
        window.quickPinLogin = quickPinLogin;

        if (window.Alpine) {
            window.Alpine.data('quickPinLogin', quickPinLogin);
        } else {
            document.addEventListener('alpine:init', () => {
                window.Alpine.data('quickPinLogin', quickPinLogin);
            });
        }
    })();
</script>
