import { router, useForm } from '@inertiajs/react';
import { useEffect, useState } from 'react';
import { Check, Copy, KeyRound, Loader2 } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { useToast } from '@/Components/Toast';
import { FormHeader, FormActions } from '@/Components/Pengelolaan/FormPage';
import UserLoginFields, { userLoginFormState } from '@/Components/Pengelolaan/UserLoginFields';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
} from '@/Components/ui/dialog';

const RESET_BTN =
    'inline-flex h-9 items-center justify-center gap-1.5 rounded-lg border border-input bg-card px-4 text-xs font-bold text-foreground transition-colors hover:border-primary hover:text-primary';

const CANCEL_BTN = RESET_BTN;

const CONFIRM_BTN =
    'inline-flex h-9 items-center justify-center gap-1.5 rounded-lg bg-linear-to-br from-violet-500 to-primary px-4 text-xs font-bold text-white shadow-sm transition-[filter] hover:brightness-105 disabled:opacity-50';

/**
 * Take the generated password back OUT of Inertia's history state.
 *
 * `oneTimePassword` is an ordinary page prop, and Inertia pushes the whole page object — props
 * included — into window.history.state on every visit (core: doPushState({ page: data })). History
 * is not encrypted here (nothing in this app calls Inertia::encryptHistory()), so after the admin
 * dismissed the modal and navigated away, pressing Back restored the prop and re-opened the modal
 * with the credential in it — and `history.state.page.props.oneTimePassword` read it out directly
 * in devtools. "Shown exactly once" has to survive the Back button.
 *
 * router.replaceProp() performs a client-side visit with replace:true and preserveState:true, so
 * the history entry is rewritten without the value while this component keeps the copy it is
 * showing. Exported so the behaviour is testable without a DOM: effects do not run under
 * `environment: 'node'`.
 */
export function scrubOneTimePassword(routerImpl = router) {
    routerImpl.replaceProp('oneTimePassword', null);
}

export default function Edit({ userLogin, roleOptions, oneTimePassword = null }) {
    const { show: showToast } = useToast();
    const [resetting, setResetting] = useState(false);
    const [confirmReset, setConfirmReset] = useState(false);

    /**
     * The generated password, held in state because the prop behind it is a FLASH: the server
     * puts it on exactly one render of this page and it is gone for good afterwards. It is never
     * written to the users table, to a log or to a file, and it crosses the one redirect it has
     * to cross as ciphertext (UserLoginController encrypts it into the flash and decrypts it in
     * edit(); the session store is a database table here). Copying it into state is what lets the
     * admin close the modal deliberately instead of it vanishing on a re-render.
     *
     * useState seeds it for the case where Inertia remounts this page after the reset redirect;
     * the effect covers the case where it re-renders the same instance with new props, and also
     * scrubs it out of the browser history entry. It is never written to the console or anywhere
     * else.
     */
    const [shownPassword, setShownPassword] = useState(oneTimePassword);
    const [copyState, setCopyState] = useState('idle'); // 'idle' | 'copied' | 'failed'

    useEffect(() => {
        if (oneTimePassword) {
            setShownPassword(oneTimePassword);
            setCopyState('idle');
            // Immediately, not on dismiss: the admin may navigate away with the modal still open,
            // and the history entry must never carry the credential either way. Guarded on a
            // truthy prop, so the null this pushes back cannot close the modal or loop.
            scrubOneTimePassword();
        }
    }, [oneTimePassword]);

    // `_method: 'put'` + post(): a PUT cannot carry multipart, so Inertia needs the spoof
    // whenever the form can include a file.
    const form = useForm({ _method: 'put', ...userLoginFormState(userLogin), Signature: null });

    const submit = (e) => {
        e.preventDefault();
        form.post(route('user-logins.update', userLogin.ID), {
            onError: () => showToast('Please check the form and try again.', 'error'),
        });
    };

    const doReset = () => {
        setResetting(true);
        // NO `only:` here on purpose: a partial reload that leaves `oneTimePassword` out would
        // consume the flash without ever showing it, and the password cannot be recovered.
        router.post(route('user-logins.reset-password', userLogin.ID), {}, {
            preserveScroll: true,
            onSuccess: () => setConfirmReset(false),
            onError: () => showToast('Password reset failed.', 'error'),
            onFinish: () => setResetting(false),
        });
    };

    const copyPassword = async () => {
        try {
            // Undefined on an insecure origin (plain http), which is why the value is also
            // rendered in a selectable read-only box below — the admin is never stuck.
            await navigator.clipboard.writeText(shownPassword);
            setCopyState('copied');
        } catch {
            setCopyState('failed');
        }
    };

    return (
        <>
            <form onSubmit={submit}>
                <FormHeader title={`Edit User Login — ${userLogin.Nama}`} backHref={route('user-logins.index')}>
                    <button type="button" onClick={() => setConfirmReset(true)} className={RESET_BTN}>
                        <KeyRound className="size-4" aria-hidden="true" />
                        Reset Password
                    </button>
                </FormHeader>

                <div className="grid gap-4">
                    {/* showPassword omitted on purpose — passwords change via Reset only.
                        `employee` is display-only: the same four columns are read-only here
                        as on Create, so this menu can never overwrite HR data. */}
                    <UserLoginFields
                        form={form}
                        roleOptions={roleOptions ?? []}
                        employee={userLogin}
                        hasSignature={userLogin.hasSignature}
                        signatureUrl={route('user-logins.signature', userLogin.ID)}
                    />
                    <FormActions form={form} cancelHref={route('user-logins.index')} submitLabel="Update" />
                </div>
            </form>

            {confirmReset && (
                <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4" role="dialog" aria-modal="true">
                    <div className="w-full max-w-md rounded-xl border border-border bg-card p-5 shadow-lg">
                        <h3 className="text-sm font-semibold text-foreground">Reset password?</h3>
                        {/* This used to say the password would be reset to `123456`. That is no
                            longer true (finding F-05): every reset now generates a fresh random
                            password. */}
                        <p className="mt-1 text-xs text-muted-foreground">
                            Sebuah password sementara acak akan dibuat untuk <strong>{userLogin.Nama}</strong> dan
                            ditampilkan <strong>satu kali saja</strong> di layar ini. Password lama tidak bisa
                            dikembalikan, dan {userLogin.Nama} wajib menggantinya saat login berikutnya.
                        </p>
                        <div className="mt-4 flex items-center justify-end gap-2">
                            <button type="button" onClick={() => setConfirmReset(false)} className={CANCEL_BTN}>Batal</button>
                            <button type="button" onClick={doReset} disabled={resetting} className={CONFIRM_BTN}>
                                {resetting ? <><Loader2 className="mr-1 size-4 animate-spin" />Mereset...</> : 'Reset Password'}
                            </button>
                        </div>
                    </div>
                </div>
            )}

            {/* Show-once modal. Closing is deliberate: Escape and clicking outside are blocked,
                and there is no X — the single button is the only way out, because dismissing it
                by accident loses the password permanently. */}
            <Dialog open={shownPassword !== null} onOpenChange={(open) => { if (! open) setShownPassword(null); }}>
                <DialogContent
                    showCloseButton={false}
                    onEscapeKeyDown={(e) => e.preventDefault()}
                    onInteractOutside={(e) => e.preventDefault()}
                >
                    <DialogHeader>
                        <DialogTitle>Password sementara untuk {userLogin.Nama}</DialogTitle>
                        <DialogDescription>
                            Ini satu-satunya kali password ini ditampilkan — password tidak disimpan
                            dan <strong>tidak bisa ditampilkan lagi</strong>. Salin dan berikan sekarang.
                            {userLogin.Nama} akan diminta menggantinya saat login berikutnya.
                        </DialogDescription>
                    </DialogHeader>

                    <div className="flex items-center gap-2">
                        {/* Read-only input, not plain text: it stays selectable + Ctrl+C-able when
                            navigator.clipboard is unavailable (insecure origin). */}
                        <input
                            readOnly
                            value={shownPassword ?? ''}
                            aria-label="Password sementara"
                            onFocus={(e) => e.target.select()}
                            className="h-9 w-full select-all rounded-lg border border-border bg-secondary px-3 font-mono text-sm tracking-[0.08em] text-foreground"
                        />
                        <button type="button" onClick={copyPassword} className={RESET_BTN}>
                            {copyState === 'copied'
                                ? <><Check className="size-4" aria-hidden="true" />Tersalin</>
                                : <><Copy className="size-4" aria-hidden="true" />Salin</>}
                        </button>
                    </div>

                    {copyState === 'failed' && (
                        <p className="text-xs text-destructive">
                            Browser menolak akses clipboard. Pilih teks di kotak di atas lalu salin manual (Ctrl+C).
                        </p>
                    )}

                    <DialogFooter>
                        <button type="button" onClick={() => setShownPassword(null)} className={CONFIRM_BTN}>
                            Saya sudah menyalinnya
                        </button>
                    </DialogFooter>
                </DialogContent>
            </Dialog>
        </>
    );
}

Edit.layout = [AppLayout];
