import { useState, type FormEvent } from 'react';
import { Form, Head, Link, router } from '@inertiajs/react';
import {
    CheckCircle2,
    KeyRound,
    Link2,
    Mail,
    PauseCircle,
    Pencil,
    PlayCircle,
    UserRound,
    UsersRound,
} from 'lucide-react';
import { PageHeader } from '@/components/crm/page-header';
import { Combobox, type ComboboxOption } from '@/components/crm/combobox';
import { NativeSelect } from '@/components/crm/native-select';
import { StatusPill } from '@/components/crm/status-badge';
import { SearchInput, FilterBar, FilterField, TableCard, DataPagination } from '@/components/crm/toolbar';
import { Button } from '@/components/ui/button';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { formatDate, formatRelative } from '@/lib/format';
import type { CustomerPortalAccount, Option, Paginated } from '@/types';

type Props = {
    accounts: Paginated<CustomerPortalAccount>;
    filters: {
        search: string | null;
        access: string;
        verification: string;
    };
    counts: {
        total: number;
        paused: number;
        unverified: number;
    };
    filterOptions: {
        access: Option[];
        verification: Option[];
    };
    can: {
        update: boolean;
        assign: boolean;
    };
};

const headClass =
    '[&_th]:text-[11px] [&_th]:font-semibold [&_th]:tracking-wide [&_th]:uppercase';

/**
 * The people who have opened a ticket-portal account.
 *
 * This is the other half of the accounts table. The Staff screen lists staff
 * only; this lists customers only, and is where the office corrects a sign-in,
 * sends a password reset, confirms an address or pauses access. Pausing stops
 * the sign-in without touching the customer record, so their jobs and tickets
 * stay exactly where they are.
 */
export default function CustomerAccountsIndex({
    accounts,
    filters,
    counts,
    filterOptions,
    can,
}: Props) {
    const [search, setSearch] = useState(filters.search ?? '');
    const [access, setAccess] = useState(filters.access);
    const [verification, setVerification] = useState(filters.verification);
    const [editing, setEditing] = useState<CustomerPortalAccount | null>(null);
    const [assigning, setAssigning] = useState<CustomerPortalAccount | null>(
        null,
    );

    const visit = (params: Record<string, string>): void => {
        const cleaned: Record<string, string> = {};

        Object.entries(params).forEach(([key, value]) => {
            if (value !== '' && value !== 'all') {
                cleaned[key] = value;
            }
        });

        router.get('/customer-accounts', cleaned, {
            preserveState: true,
            preserveScroll: true,
            replace: true,
        });
    };

    const applyFilters = (event: FormEvent): void => {
        event.preventDefault();
        visit({ search: search.trim(), access, verification });
    };

    const resetFilters = (): void => {
        setSearch('');
        setAccess('all');
        setVerification('all');
        router.get('/customer-accounts', {}, { preserveScroll: true, replace: true });
    };

    const setAccessState = (account: CustomerPortalAccount): void => {
        const next = !account.is_locked;
        const confirmed = window.confirm(
            next
                ? `Pause portal access for ${account.name}? They will be signed out and cannot sign in again until somebody resumes it. Their customer record, jobs and tickets stay exactly as they are.`
                : `Let ${account.name} sign in to the ticket portal again?`,
        );

        if (!confirmed) {
            return;
        }

        router.post(
            `/customer-accounts/${account.id}/access`,
            { locked: next },
            { preserveScroll: true },
        );
    };

    const sendReset = (account: CustomerPortalAccount): void => {
        router.post(
            `/customer-accounts/${account.id}/password-reset`,
            {},
            { preserveScroll: true },
        );
    };

    const resendVerification = (account: CustomerPortalAccount): void => {
        router.post(
            `/customer-accounts/${account.id}/verification`,
            {},
            { preserveScroll: true },
        );
    };

    return (
        <>
            <Head title="Customer accounts" />

            <div className="flex flex-col gap-5">
                <PageHeader
                    eyebrow={
                        <>
                            <UsersRound className="size-3.5 text-solar" />
                            <span>
                                {counts.total} portal account
                                {counts.total === 1 ? '' : 's'}
                                {counts.paused > 0
                                    ? ` · ${counts.paused} paused`
                                    : ''}
                                {counts.unverified > 0
                                    ? ` · ${counts.unverified} unconfirmed`
                                    : ''}
                            </span>
                        </>
                    }
                    title="Customer accounts"
                    description="The sign-ins customers use for the ticket portal. Fix a name or address, send a password reset, confirm an email, pause access, or move a sign-in to the customer record it belongs to."
                />

                <form onSubmit={applyFilters}>
                    <FilterBar
                        actions={
                            <>
                                <Button type="submit" size="sm">
                                    Apply
                                </Button>
                                <Button
                                    type="button"
                                    variant="ghost"
                                    size="sm"
                                    onClick={resetFilters}
                                >
                                    Reset
                                </Button>
                            </>
                        }
                    >
                        <SearchInput
                            value={search}
                            onChange={setSearch}
                            placeholder="Search name, email, phone or customer number"
                        />

                        <FilterField label="Access" className="w-40">
                            <NativeSelect
                                className="h-9"
                                value={access}
                                onChange={(event) =>
                                    setAccess(event.target.value)
                                }
                                aria-label="Filter by access"
                            >
                                {filterOptions.access.map((option) => (
                                    <option
                                        key={option.value}
                                        value={option.value}
                                    >
                                        {option.label}
                                    </option>
                                ))}
                            </NativeSelect>
                        </FilterField>

                        <FilterField label="Email" className="w-44">
                            <NativeSelect
                                className="h-9"
                                value={verification}
                                onChange={(event) =>
                                    setVerification(event.target.value)
                                }
                                aria-label="Filter by email confirmation"
                            >
                                {filterOptions.verification.map((option) => (
                                    <option
                                        key={option.value}
                                        value={option.value}
                                    >
                                        {option.label}
                                    </option>
                                ))}
                            </NativeSelect>
                        </FilterField>
                    </FilterBar>
                </form>

                {accounts.data.length === 0 ? (
                    <div className="rounded-2xl bg-card p-10 text-center ring-1 ring-hairline">
                        <span className="mx-auto flex size-10 items-center justify-center rounded-full bg-muted text-muted-foreground">
                            <UserRound className="size-5" />
                        </span>
                        <p className="mt-3 text-sm font-medium">
                            No customer accounts match
                        </p>
                        <p className="mx-auto mt-1 max-w-md text-xs text-muted-foreground">
                            Customers get an account when they sign up from the
                            ticket portal. Their customer record is in
                            Customers, whether or not they have signed in.
                        </p>
                    </div>
                ) : (
                    <TableCard>
                        <Table>
                            <TableHeader className={headClass}>
                                <TableRow>
                                    <TableHead>Customer</TableHead>
                                    <TableHead>Sign-in</TableHead>
                                    <TableHead>Last sign-in</TableHead>
                                    <TableHead>Status</TableHead>
                                    <TableHead className="text-right">
                                        Actions
                                    </TableHead>
                                </TableRow>
                            </TableHeader>
                            <TableBody>
                                {accounts.data.map((account) => (
                                    <TableRow key={account.id}>
                                        <TableCell>
                                            {account.customer ? (
                                                <>
                                                    <Link
                                                        href={`/customers/${account.customer.id}`}
                                                        className="font-medium hover:underline"
                                                    >
                                                        {account.customer.name}
                                                    </Link>
                                                    <p className="font-mono text-[11px] text-muted-foreground">
                                                        {
                                                            account.customer
                                                                .customer_number
                                                        }
                                                    </p>
                                                </>
                                            ) : (
                                                <span className="text-sm text-muted-foreground">
                                                    No customer record
                                                </span>
                                            )}
                                        </TableCell>
                                        <TableCell>
                                            <p className="text-sm">
                                                {account.name}
                                            </p>
                                            <p className="text-xs text-muted-foreground">
                                                {account.email}
                                            </p>
                                            {account.phone ? (
                                                <p className="text-xs text-muted-foreground">
                                                    {account.phone}
                                                </p>
                                            ) : null}
                                        </TableCell>
                                        <TableCell className="text-xs text-muted-foreground">
                                            {account.last_login_at ? (
                                                <>
                                                    {formatRelative(
                                                        account.last_login_at,
                                                    )}
                                                    <span className="block">
                                                        {formatDate(
                                                            account.last_login_at,
                                                        )}
                                                    </span>
                                                </>
                                            ) : (
                                                'Never'
                                            )}
                                        </TableCell>
                                        <TableCell>
                                            <div className="flex flex-wrap gap-1.5">
                                                {account.is_locked ? (
                                                    <StatusPill tone="amber">
                                                        Paused
                                                    </StatusPill>
                                                ) : (
                                                    <StatusPill tone="emerald">
                                                        Can sign in
                                                    </StatusPill>
                                                )}
                                                {account.verified ? (
                                                    <StatusPill tone="slate">
                                                        Confirmed
                                                    </StatusPill>
                                                ) : (
                                                    <StatusPill tone="red">
                                                        Not confirmed
                                                    </StatusPill>
                                                )}
                                            </div>
                                        </TableCell>
                                        <TableCell>
                                            <div className="flex flex-wrap items-center justify-end gap-1">
                                                {can.update ? (
                                                    <>
                                                        <Button
                                                            type="button"
                                                            variant="ghost"
                                                            size="sm"
                                                            onClick={() =>
                                                                setEditing(
                                                                    account,
                                                                )
                                                            }
                                                        >
                                                            <Pencil />
                                                            Edit
                                                        </Button>
                                                        {can.assign ? (
                                                            <Button
                                                                type="button"
                                                                variant="ghost"
                                                                size="sm"
                                                                onClick={() =>
                                                                    setAssigning(
                                                                        account,
                                                                    )
                                                                }
                                                                title="Move this sign-in to the customer record it belongs to"
                                                            >
                                                                <Link2 />
                                                                Assign
                                                            </Button>
                                                        ) : null}
                                                        <Button
                                                            type="button"
                                                            variant="ghost"
                                                            size="sm"
                                                            onClick={() =>
                                                                sendReset(
                                                                    account,
                                                                )
                                                            }
                                                            title="Email a password reset link"
                                                        >
                                                            <KeyRound />
                                                            Reset
                                                        </Button>
                                                        {!account.verified ? (
                                                            <Button
                                                                type="button"
                                                                variant="ghost"
                                                                size="sm"
                                                                onClick={() =>
                                                                    resendVerification(
                                                                        account,
                                                                    )
                                                                }
                                                                title="Send the confirmation email again"
                                                            >
                                                                <Mail />
                                                                Confirm
                                                            </Button>
                                                        ) : null}
                                                        <Button
                                                            type="button"
                                                            variant="ghost"
                                                            size="sm"
                                                            onClick={() =>
                                                                setAccessState(
                                                                    account,
                                                                )
                                                            }
                                                        >
                                                            {account.is_locked ? (
                                                                <>
                                                                    <PlayCircle />
                                                                    Resume
                                                                </>
                                                            ) : (
                                                                <>
                                                                    <PauseCircle />
                                                                    Pause
                                                                </>
                                                            )}
                                                        </Button>
                                                    </>
                                                ) : (
                                                    <span className="text-xs text-muted-foreground">
                                                        View only
                                                    </span>
                                                )}
                                            </div>
                                        </TableCell>
                                    </TableRow>
                                ))}
                            </TableBody>
                        </Table>

                        <DataPagination page={accounts} noun="accounts" />
                    </TableCard>
                )}

                <p className="flex items-start gap-2 text-xs leading-relaxed text-muted-foreground">
                    <CheckCircle2 className="mt-0.5 size-3.5 shrink-0" />
                    <span>
                        These are sign-ins only. A customer&rsquo;s contact
                        details, installation address and account manager are
                        edited on their customer record, which this screen links
                        to. Pausing an account never changes the record — it
                        only stops the portal sign-in. Assigning a sign-in to a
                        different customer never edits either record; it only
                        changes whose jobs and tickets the portal shows.
                    </span>
                </p>
            </div>

            <EditDialog
                account={editing}
                onClose={() => setEditing(null)}
            />

            {/* Keyed on the account so the picker starts from that row's own
                customer rather than the one chosen last time. */}
            <AssignDialog
                key={assigning?.id ?? 'none'}
                account={assigning}
                onClose={() => setAssigning(null)}
            />
        </>
    );
}

/**
 * Moving a sign-in to the customer record it belongs to.
 *
 * The link is made by the portal at sign-up, and a phone number two people
 * share, or a record duplicated at the time, can put it on the wrong
 * household. The picker searches the whole customer database, and the chosen
 * record is the only thing that changes: both customer records stay exactly as
 * they are.
 */
function AssignDialog({
    account,
    onClose,
}: {
    account: CustomerPortalAccount | null;
    onClose: () => void;
}) {
    const [customerId, setCustomerId] = useState<number | null>(
        account?.customer?.id ?? null,
    );

    // The current record is seeded as an option so the field shows what the
    // sign-in points at until somebody searches for something else.
    const option: ComboboxOption[] = account?.customer
        ? [
              {
                  value: account.customer.id,
                  label: account.customer.name,
                  note: account.customer.customer_number,
              },
          ]
        : [];

    return (
        <Dialog
            open={account !== null}
            onOpenChange={(open) => {
                if (!open) {
                    onClose();
                }
            }}
        >
            <DialogContent>
                <DialogHeader>
                    <DialogTitle>Assign to a customer</DialogTitle>
                    <DialogDescription>
                        Move this sign-in to the customer record it belongs to.
                    </DialogDescription>
                </DialogHeader>

                {account ? (
                    <Form
                        action={`/customer-accounts/${account.id}/customer`}
                        method="post"
                        onSuccess={onClose}
                        className="flex flex-col gap-4"
                    >
                        {({ processing, errors }) => (
                            <>
                                <p className="rounded-lg bg-muted/60 p-3 text-xs leading-relaxed text-muted-foreground">
                                    {account.name} signs in with{' '}
                                    <span className="font-medium text-foreground">
                                        {account.email}
                                    </span>
                                    .{' '}
                                    {account.customer ? (
                                        <>
                                            The portal currently shows{' '}
                                            <span className="font-medium text-foreground">
                                                {account.customer.name}
                                            </span>
                                            &rsquo;s jobs and tickets.
                                        </>
                                    ) : (
                                        'The portal does not show any customer yet.'
                                    )}
                                </p>

                                <div className="grid gap-2">
                                    <Label htmlFor="assign_customer">
                                        Customer record
                                    </Label>
                                    <Combobox
                                        id="assign_customer"
                                        name="customer_id"
                                        options={option}
                                        value={customerId}
                                        onChange={(value) =>
                                            setCustomerId(value)
                                        }
                                        remote={{
                                            url: '/lookups/customers',
                                            minChars: 2,
                                        }}
                                        placeholder="Search by name, number, phone or email"
                                        emptyLabel="No customers match"
                                    />
                                    <p className="text-[11px] leading-snug text-muted-foreground">
                                        From their next page load, this sign-in
                                        sees the chosen customer&rsquo;s jobs,
                                        tickets and reports. Neither customer
                                        record is edited, and the sign-in keeps
                                        its own name, email and phone.
                                    </p>
                                    {errors.customer_id ? (
                                        <p className="text-xs text-red-600 dark:text-red-400">
                                            {errors.customer_id}
                                        </p>
                                    ) : null}
                                </div>

                                <div className="flex flex-wrap items-center justify-end gap-2">
                                    <Button
                                        type="button"
                                        variant="ghost"
                                        onClick={onClose}
                                    >
                                        Cancel
                                    </Button>
                                    <Button
                                        type="submit"
                                        disabled={
                                            processing || customerId === null
                                        }
                                    >
                                        Assign the sign-in
                                    </Button>
                                </div>
                            </>
                        )}
                    </Form>
                ) : null}
            </DialogContent>
        </Dialog>
    );
}

/**
 * Correcting the sign-in details. Changing the email also changes the address
 * we contact the customer on, so it is sent a confirmation and has to confirm
 * the new address before the portal opens again.
 */
function EditDialog({
    account,
    onClose,
}: {
    account: CustomerPortalAccount | null;
    onClose: () => void;
}) {
    return (
        <Dialog
            open={account !== null}
            onOpenChange={(open) => {
                if (!open) {
                    onClose();
                }
            }}
        >
            <DialogContent>
                <DialogHeader>
                    <DialogTitle>Edit the sign-in</DialogTitle>
                    <DialogDescription>
                        {account?.customer
                            ? `Portal account for ${account.customer.name} (${account.customer.customer_number}).`
                            : 'Portal account.'}
                    </DialogDescription>
                </DialogHeader>

                {account ? (
                    <Form
                        action={`/customer-accounts/${account.id}`}
                        method="put"
                        onSuccess={onClose}
                        className="flex flex-col gap-4"
                    >
                        {({ processing, errors }) => (
                            <>
                                <div className="grid gap-2">
                                    <Label htmlFor="account_name">
                                        Name on the account
                                    </Label>
                                    <Input
                                        id="account_name"
                                        name="name"
                                        required
                                        defaultValue={account.name}
                                    />
                                    {errors.name ? (
                                        <p className="text-xs text-red-600 dark:text-red-400">
                                            {errors.name}
                                        </p>
                                    ) : null}
                                </div>

                                <div className="grid gap-2">
                                    <Label htmlFor="account_email">
                                        Sign-in email
                                    </Label>
                                    <Input
                                        id="account_email"
                                        name="email"
                                        type="email"
                                        required
                                        defaultValue={account.email}
                                    />
                                    <p className="text-[11px] leading-snug text-muted-foreground">
                                        This is also the customer&rsquo;s
                                        contact email. Changing it signs them
                                        out of the portal until they confirm the
                                        new address, and it is shown on their
                                        customer record.
                                    </p>
                                    {errors.email ? (
                                        <p className="text-xs text-red-600 dark:text-red-400">
                                            {errors.email}
                                        </p>
                                    ) : null}
                                </div>

                                <div className="grid gap-2">
                                    <Label htmlFor="account_phone">
                                        Phone
                                    </Label>
                                    <Input
                                        id="account_phone"
                                        name="phone"
                                        type="tel"
                                        defaultValue={account.phone ?? ''}
                                    />
                                    {errors.phone ? (
                                        <p className="text-xs text-red-600 dark:text-red-400">
                                            {errors.phone}
                                        </p>
                                    ) : null}
                                </div>

                                <div className="flex flex-wrap items-center justify-end gap-2">
                                    <Button
                                        type="button"
                                        variant="ghost"
                                        onClick={onClose}
                                    >
                                        Cancel
                                    </Button>
                                    <Button type="submit" disabled={processing}>
                                        Save the account
                                    </Button>
                                </div>
                            </>
                        )}
                    </Form>
                ) : null}
            </DialogContent>
        </Dialog>
    );
}
