import { useState } from "react";
import { Form } from "@inertiajs/react";
import {
    ArrowRightLeft,
    House,
    Search,
    UserPlus,
    type LucideIcon,
} from "lucide-react";
import SiteController from "@/actions/App/Http/Controllers/SiteController";
import { Combobox } from "@/components/crm/combobox";
import { FormField, NativeSelect } from "@/components/crm/native-select";
import { Button } from "@/components/ui/button";
import {
    Dialog,
    DialogClose,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
    DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { toDateInputValue } from "@/lib/format";
import { cn } from "@/lib/utils";
import type { Option } from "@/types";

type OwnershipReason = Option & { description: string };

type Props = {
    /** The customer the house is leaving: the customer in the transfer route. */
    ownerId: number;
    site: { id: number; label: string | null; address: string };
    /** The name on the record now, for explaining what does not move with it. */
    currentOwnerName: string | null;
    reasons: OwnershipReason[];
    customerTypes: Option[];
    variant?: "outline" | "ghost" | "default";
    label?: string;
};

/**
 * Handing a house to a new owner.
 *
 * The office uses this the week a settlement goes through, so it asks for the
 * four things that are actually known then — who took it over, the day it
 * changed hands, why, and anything worth remembering — and nothing else. The
 * buyer is usually not on file yet, which is why the new owner can be typed in
 * here rather than sending somebody off to the customer form first.
 *
 * What happens on save is spelled out on the dialog itself, because "which jobs
 * follow the house?" is the question that decides whether it is safe to press
 * the button: the work still open at the address moves, the work already
 * finished stays with the owner who commissioned it, and the address keeps a
 * record of both.
 */
export function TransferOwnershipDialog({
    ownerId,
    site,
    currentOwnerName,
    reasons,
    customerTypes,
    variant = "outline",
    label = "Transfer ownership",
}: Props) {
    const [open, setOpen] = useState(false);
    const [mode, setMode] = useState<"existing" | "new">("existing");
    const [customerId, setCustomerId] = useState<number | null>(null);
    const [reason, setReason] = useState<string>(reasons[0]?.value ?? "");

    const selectedReason = reasons.find((option) => option.value === reason);
    const property = site.label ?? site.address;

    return (
        <Dialog
            open={open}
            onOpenChange={(next) => {
                setOpen(next);

                if (!next) {
                    setCustomerId(null);
                    setMode("existing");
                    setReason(reasons[0]?.value ?? "");
                }
            }}
        >
            <DialogTrigger asChild>
                <Button variant={variant} size="sm" data-test="transfer-ownership-button">
                    <ArrowRightLeft />
                    {label}
                </Button>
            </DialogTrigger>

            <DialogContent className="max-h-[85vh] overflow-y-auto sm:max-w-2xl">
                <DialogHeader>
                    <DialogTitle>Hand this property to a new owner</DialogTitle>
                    <DialogDescription>
                        {property} · {site.address}
                    </DialogDescription>
                </DialogHeader>

                <Form
                    {...SiteController.transfer.form({
                        customer: ownerId,
                        site: site.id,
                    })}
                    options={{ preserveScroll: true }}
                    onSuccess={() => setOpen(false)}
                    className="grid gap-4"
                >
                    {({ processing, errors }) => (
                        <>
                            <div className="bg-muted/60 grid gap-1 rounded-lg p-3 text-xs leading-relaxed">
                                <p className="text-foreground font-medium">
                                    What moves, and what stays
                                </p>
                                <p className="text-muted-foreground">
                                    The house and every job still open at it
                                    move to the new owner, along with the
                                    tickets and files attached to those jobs —
                                    they are about the address, and the person
                                    who now has to be phoned about them is the
                                    new owner.
                                    {currentOwnerName
                                        ? ` Finished and cancelled work stays with ${currentOwnerName}, and so do the invoices behind it.`
                                        : " Finished and cancelled work stays with the owner who commissioned it, and so do the invoices behind it."}
                                </p>
                                <p className="text-muted-foreground">
                                    Whoever held this property before stays in
                                    its history, with the dates and the reason.
                                </p>
                            </div>

                            <div
                                role="radiogroup"
                                aria-label="Who is taking over the property"
                                className="grid gap-2 sm:grid-cols-2"
                            >
                                <ModeButton
                                    selected={mode === "existing"}
                                    icon={Search}
                                    title="A customer already on file"
                                    note="Search the customer list."
                                    onClick={() => setMode("existing")}
                                />
                                <ModeButton
                                    selected={mode === "new"}
                                    icon={UserPlus}
                                    title="Somebody new"
                                    note="Create their record as you go."
                                    onClick={() => setMode("new")}
                                />
                            </div>

                            {mode === "existing" ? (
                                <div className="grid gap-2">
                                    <span className="text-sm font-medium">
                                        New owner
                                        <span
                                            className="text-destructive"
                                            aria-hidden
                                        >
                                            *
                                        </span>
                                    </span>
                                    <Combobox
                                        id="customer_id"
                                        name="customer_id"
                                        options={[]}
                                        value={customerId}
                                        onChange={(value) =>
                                            setCustomerId(value)
                                        }
                                        remote={{
                                            url: "/lookups/customers",
                                            minChars: 2,
                                        }}
                                        placeholder="Search by name, number, phone or email"
                                        emptyLabel="No customers match"
                                    />
                                    {errors.customer_id ? (
                                        <p
                                            className="text-destructive text-xs font-medium"
                                            role="alert"
                                        >
                                            {errors.customer_id}
                                        </p>
                                    ) : null}
                                </div>
                            ) : (
                                <div className="grid gap-4 sm:grid-cols-2">
                                    <FormField
                                        label="New owner's name"
                                        htmlFor="new_owner_name"
                                        error={errors.new_owner_name}
                                        required
                                        hint="A person, or the company taking it on."
                                        className="sm:col-span-2"
                                    >
                                        <Input
                                            id="new_owner_name"
                                            name="new_owner_name"
                                            placeholder="Priya Raman"
                                            required
                                        />
                                    </FormField>

                                    <FormField
                                        label="Owner type"
                                        htmlFor="new_owner_type"
                                        error={errors.new_owner_type}
                                        hint="Decides whether the name is a person or a company."
                                    >
                                        <NativeSelect
                                            id="new_owner_type"
                                            name="new_owner_type"
                                            defaultValue="residential"
                                        >
                                            {customerTypes.map((option) => (
                                                <option
                                                    key={option.value}
                                                    value={option.value}
                                                >
                                                    {option.label}
                                                </option>
                                            ))}
                                        </NativeSelect>
                                    </FormField>

                                    <FormField
                                        label="Phone"
                                        htmlFor="new_owner_phone"
                                        error={errors.new_owner_phone}
                                    >
                                        <Input
                                            id="new_owner_phone"
                                            name="new_owner_phone"
                                            type="tel"
                                            placeholder="0400 000 000"
                                        />
                                    </FormField>

                                    <FormField
                                        label="Email"
                                        htmlFor="new_owner_email"
                                        error={errors.new_owner_email}
                                        className="sm:col-span-2"
                                        hint="Enough to reach them; the rest of their record can be filled in later."
                                    >
                                        <Input
                                            id="new_owner_email"
                                            name="new_owner_email"
                                            type="email"
                                        />
                                    </FormField>
                                </div>
                            )}

                            <div className="grid gap-4 sm:grid-cols-2">
                                <FormField
                                    label="Date it changed hands"
                                    htmlFor="effective_on"
                                    error={errors.effective_on}
                                    required
                                    hint="The settlement or handover date."
                                >
                                    <Input
                                        id="effective_on"
                                        name="effective_on"
                                        type="date"
                                        required
                                        max={toDateInputValue(
                                            new Date().toISOString(),
                                        )}
                                        defaultValue={toDateInputValue(
                                            new Date().toISOString(),
                                        )}
                                    />
                                </FormField>

                                <FormField
                                    label="Why it changed hands"
                                    htmlFor="reason"
                                    error={errors.reason}
                                    required
                                    hint={selectedReason?.description ?? null}
                                >
                                    <NativeSelect
                                        id="reason"
                                        name="reason"
                                        required
                                        value={reason}
                                        onChange={(event) =>
                                            setReason(event.target.value)
                                        }
                                    >
                                        {reasons.map((option) => (
                                            <option
                                                key={option.value}
                                                value={option.value}
                                            >
                                                {option.label}
                                            </option>
                                        ))}
                                    </NativeSelect>
                                </FormField>
                            </div>

                            <FormField
                                label="Notes"
                                htmlFor="notes"
                                error={errors.notes}
                                hint="Shown on the property's ownership history, permanently."
                            >
                                <textarea
                                    id="notes"
                                    name="notes"
                                    rows={3}
                                    className="border-input dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 w-full rounded-md border bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:ring-[3px]"
                                    placeholder="Sold at auction; keys handed over the same day."
                                />
                            </FormField>

                            <CheckboxField
                                name="include_closed_jobs"
                                label="Move the finished work too"
                                hint="Leave this off unless the owner on file was simply wrong — finished jobs and their invoices are the record of who commissioned them."
                            />

                            <DialogFooter className="mt-1">
                                <DialogClose asChild>
                                    <Button type="button" variant="ghost">
                                        Cancel
                                    </Button>
                                </DialogClose>
                                <Button
                                    type="submit"
                                    disabled={
                                        processing ||
                                        (mode === "existing" &&
                                            customerId === null)
                                    }
                                    data-test="transfer-ownership-submit"
                                >
                                    <House />
                                    {processing
                                        ? "Handing over…"
                                        : "Hand over the property"}
                                </Button>
                            </DialogFooter>
                        </>
                    )}
                </Form>
            </DialogContent>
        </Dialog>
    );
}

/**
 * One of the two ways to name the new owner. A pair of buttons rather than a
 * select, because which one is chosen changes the fields underneath it.
 */
function ModeButton({
    selected,
    icon: Icon,
    title,
    note,
    onClick,
}: {
    selected: boolean;
    icon: LucideIcon;
    title: string;
    note: string;
    onClick: () => void;
}) {
    return (
        <button
            type="button"
            role="radio"
            aria-checked={selected}
            onClick={onClick}
            className={cn(
                "ring-hairline bg-surface/50 focus-visible:ring-ring/50 rounded-lg p-3 text-left ring-1 ring-inset transition outline-none focus-visible:ring-[3px]",
                selected
                    ? "bg-accent ring-solar/50"
                    : "hover:ring-foreground/20",
            )}
        >
            <span className="flex items-center gap-2 text-sm font-medium">
                <Icon className="size-4 shrink-0" />
                {title}
            </span>
            <span className="text-muted-foreground mt-1 block text-xs">
                {note}
            </span>
        </button>
    );
}

/**
 * A boolean that always submits a value.
 *
 * Inertia's Form reads plain form values and Laravel's `boolean` rule rejects a
 * bare "on", so the hidden input supplies "0" for the unchecked case. The same
 * helper exists on the job form; it is repeated rather than shared because this
 * dialog is the only other place that needs it.
 */
function CheckboxField({
    name,
    label,
    hint,
}: {
    name: string;
    label: string;
    hint?: string | null;
}) {
    return (
        <div className="grid gap-1">
            <label className="flex items-start gap-2 text-sm">
                <input type="hidden" name={name} value="0" />
                <input
                    type="checkbox"
                    name={name}
                    value="1"
                    className="border-input mt-0.5 size-4 shrink-0 rounded border"
                />
                <span>
                    {label}
                    {hint ? (
                        <span className="text-muted-foreground block text-xs">
                            {hint}
                        </span>
                    ) : null}
                </span>
            </label>
        </div>
    );
}
