import { Form } from '@inertiajs/react';
import {
    Building2,
    Check,
    ChevronDown,
    CreditCard,
    Search,
    WalletCards,
} from 'lucide-react';
import { useEffect, useMemo, useRef, useState } from 'react';
import AccountController from '@/actions/App/Http/Controllers/AccountController';
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { cn } from '@/lib/utils';
import type { AccountRow, AccountType, BankOption } from '@/types/account';

type AccountFormDialogProps = {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    accountType: AccountType;
    banks: BankOption[];
    account?: AccountRow | null;
};

const cardTypeOptions = [
    {
        value: 'debit',
        label: 'Debit',
        icon: WalletCards,
    },
    {
        value: 'credit',
        label: 'Credit',
        icon: CreditCard,
    },
] as const;

type BankSearchSelectProps = {
    banks: BankOption[];
    value: number | null;
    onChange: (bankId: number) => void;
    required?: boolean;
    error?: string;
};

function BankSearchSelect({
    banks,
    value,
    onChange,
    required = false,
    error,
}: BankSearchSelectProps) {
    const containerRef = useRef<HTMLDivElement>(null);
    const [isOpen, setIsOpen] = useState(false);
    const [search, setSearch] = useState('');

    const selectedBank = useMemo(
        () => banks.find((bank) => bank.id === value) ?? null,
        [banks, value],
    );

    const filteredBanks = useMemo(() => {
        const term = search.trim().toLowerCase();

        if (term === '') {
            return banks;
        }

        return banks.filter(
            (bank) =>
                bank.name.toLowerCase().includes(term) ||
                bank.short_name.toLowerCase().includes(term) ||
                bank.ownership_type.toLowerCase().includes(term),
        );
    }, [banks, search]);

    useEffect(() => {
        if (!isOpen) {
            return;
        }

        const handlePointerDown = (event: MouseEvent) => {
            if (
                containerRef.current &&
                !containerRef.current.contains(event.target as Node)
            ) {
                setIsOpen(false);
                setSearch('');
            }
        };

        document.addEventListener('mousedown', handlePointerDown);

        return () => {
            document.removeEventListener('mousedown', handlePointerDown);
        };
    }, [isOpen]);

    return (
        <div className="grid gap-2">
            <input
                type="hidden"
                name="bank_id"
                value={value ?? ''}
                required={required}
            />
            <div ref={containerRef} className="relative">
                <Button
                    type="button"
                    variant="outline"
                    aria-expanded={isOpen}
                    aria-haspopup="listbox"
                    className={cn(
                        'h-9 w-full justify-between font-normal',
                        error && 'border-destructive',
                    )}
                    onClick={() => setIsOpen((previous) => !previous)}
                >
                    <span className="flex items-center gap-2 truncate">
                        <Building2 className="size-4 shrink-0 text-muted-foreground" />
                        {selectedBank ? selectedBank.name : 'Select a bank'}
                    </span>
                    <ChevronDown
                        className={cn(
                            'size-4 shrink-0 opacity-50 transition-transform',
                            isOpen && 'rotate-180',
                        )}
                    />
                </Button>

                {isOpen && (
                    <div className="absolute z-50 mt-1 w-full rounded-md border bg-popover text-popover-foreground shadow-md">
                        <div className="border-b p-2">
                            <div className="relative">
                                <Search className="absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground" />
                                <Input
                                    value={search}
                                    onChange={(event) =>
                                        setSearch(event.target.value)
                                    }
                                    placeholder="Search banks..."
                                    className="pl-8"
                                    autoFocus
                                />
                            </div>
                        </div>
                        <ul
                            role="listbox"
                            className="max-h-48 overflow-y-auto p-1"
                        >
                            {filteredBanks.length > 0 ? (
                                filteredBanks.map((bank) => {
                                    const isSelected = bank.id === value;

                                    return (
                                        <li key={bank.id}>
                                            <button
                                                type="button"
                                                role="option"
                                                aria-selected={isSelected}
                                                className={cn(
                                                    'flex w-full items-start gap-2 rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-accent-foreground',
                                                    isSelected &&
                                                        'bg-accent text-accent-foreground',
                                                )}
                                                onClick={() => {
                                                    onChange(bank.id);
                                                    setIsOpen(false);
                                                    setSearch('');
                                                }}
                                            >
                                                <Building2 className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
                                                <span className="min-w-0 flex-1">
                                                    <span className="block truncate font-medium">
                                                        {bank.name}
                                                    </span>
                                                    <span className="block text-xs text-muted-foreground">
                                                        {bank.ownership_type}
                                                    </span>
                                                </span>
                                                {isSelected && (
                                                    <Check className="mt-0.5 size-4 shrink-0" />
                                                )}
                                            </button>
                                        </li>
                                    );
                                })
                            ) : (
                                <li className="px-2 py-6 text-center text-sm text-muted-foreground">
                                    No banks found.
                                </li>
                            )}
                        </ul>
                    </div>
                )}
            </div>
            <InputError message={error} />
        </div>
    );
}

type CardTypeSelectProps = {
    value: string;
    onChange: (value: string) => void;
    error?: string;
};

function CardTypeSelect({ value, onChange, error }: CardTypeSelectProps) {
    const selectedOption = cardTypeOptions.find(
        (option) => option.value === value,
    );
    const SelectedIcon = selectedOption?.icon;

    return (
        <div className="grid gap-2">
            <input type="hidden" name="card_type" value={value} required />
            <Select value={value} onValueChange={onChange} required>
                <SelectTrigger
                    className={cn('w-full', error && 'border-destructive')}
                >
                    {selectedOption && SelectedIcon ? (
                        <span className="flex items-center gap-2 truncate">
                            <SelectedIcon className="size-4 shrink-0 text-muted-foreground" />
                            <span>{selectedOption.label}</span>
                        </span>
                    ) : (
                        <SelectValue placeholder="Select card type" />
                    )}
                </SelectTrigger>
                <SelectContent>
                    {cardTypeOptions.map(
                        ({ value: optionValue, label, icon: Icon }) => (
                            <SelectItem key={optionValue} value={optionValue}>
                                <Icon className="size-4 text-muted-foreground" />
                                {label}
                            </SelectItem>
                        ),
                    )}
                </SelectContent>
            </Select>
            <InputError message={error} />
        </div>
    );
}

type AccountFormDialogFormProps = {
    account: AccountRow | null;
    accountType: AccountType;
    banks: BankOption[];
    onOpenChange: (open: boolean) => void;
};

function AccountFormDialogForm({
    account,
    accountType,
    banks,
    onOpenChange,
}: AccountFormDialogFormProps) {
    const isEditing = account !== null;
    const [hasCard, setHasCard] = useState(account?.has_card ?? false);
    const [bankId, setBankId] = useState<number | null>(
        account?.bank?.id ?? null,
    );
    const [cardType, setCardType] = useState(account?.card_type ?? '');

    const formProps = isEditing
        ? AccountController.update.form(account.id)
        : AccountController.store.form();

    return (
        <Form
            {...formProps}
            options={{
                preserveScroll: true,
            }}
            onSuccess={() => onOpenChange(false)}
            className="space-y-4"
        >
            {({ processing, errors }) => (
                <>
                    {!isEditing && (
                        <input
                            type="hidden"
                            name="account_type"
                            value={accountType}
                        />
                    )}

                    {accountType !== 'cash' && (
                        <div className="grid gap-2">
                            <Label htmlFor="bank_id">Bank</Label>
                            <BankSearchSelect
                                banks={banks}
                                value={bankId}
                                onChange={setBankId}
                                required
                                error={errors.bank_id}
                            />
                        </div>
                    )}

                    <div className="grid gap-2">
                        <Label htmlFor="account_name">Account Name</Label>
                        <Input
                            id="account_name"
                            name="account_name"
                            defaultValue={account?.account_name ?? ''}
                            required
                            placeholder="Account name"
                        />
                        <InputError message={errors.account_name} />
                    </div>

                    <div className="grid gap-2">
                        <Label htmlFor="account_holder_name">
                            Account Holder Name
                        </Label>
                        <Input
                            id="account_holder_name"
                            name="account_holder_name"
                            defaultValue={account?.account_holder_name ?? ''}
                            required
                            placeholder="Account holder name"
                        />
                        <InputError message={errors.account_holder_name} />
                    </div>

                    {accountType !== 'cash' && (
                        <div className="grid gap-2">
                            <Label htmlFor="account_number">
                                Account Number
                            </Label>
                            <Input
                                id="account_number"
                                name="account_number"
                                defaultValue={account?.account_number ?? ''}
                                required
                                placeholder="Account number"
                            />
                            <InputError message={errors.account_number} />
                        </div>
                    )}

                    {!isEditing && (
                        <div className="grid gap-2">
                            <Label htmlFor="opening_balance">
                                Opening Balance
                            </Label>
                            <Input
                                id="opening_balance"
                                name="opening_balance"
                                type="number"
                                min="0"
                                step="0.01"
                                defaultValue="0"
                                required
                                placeholder="0.00"
                            />
                            <InputError message={errors.opening_balance} />
                        </div>
                    )}

                    {accountType === 'bank' && (
                        <>
                            <div className="flex items-center gap-2">
                                <input
                                    type="hidden"
                                    name="has_card"
                                    value="0"
                                />
                                <Checkbox
                                    id="has_card"
                                    name="has_card"
                                    value="1"
                                    checked={hasCard}
                                    onCheckedChange={(checked) =>
                                        setHasCard(checked === true)
                                    }
                                />
                                <Label htmlFor="has_card">Has card</Label>
                            </div>
                            <InputError message={errors.has_card} />

                            {hasCard && (
                                <>
                                    <div className="grid gap-2">
                                        <Label htmlFor="card_type">
                                            Card Type
                                        </Label>
                                        <CardTypeSelect
                                            value={cardType}
                                            onChange={setCardType}
                                            error={errors.card_type}
                                        />
                                    </div>

                                    <div className="grid gap-2">
                                        <Label htmlFor="card_number">
                                            Card Number
                                        </Label>
                                        <Input
                                            id="card_number"
                                            name="card_number"
                                            defaultValue={
                                                account?.card_number ?? ''
                                            }
                                            placeholder="Card number"
                                        />
                                        <InputError
                                            message={errors.card_number}
                                        />
                                    </div>

                                    <div className="grid gap-2">
                                        <Label htmlFor="card_expiry_date">
                                            Card Expiry Date
                                        </Label>
                                        <Input
                                            id="card_expiry_date"
                                            name="card_expiry_date"
                                            type="date"
                                            defaultValue=""
                                            placeholder="Expiry date"
                                        />
                                        <InputError
                                            message={errors.card_expiry_date}
                                        />
                                    </div>
                                </>
                            )}
                        </>
                    )}

                    <div className="flex items-center gap-2">
                        <input type="hidden" name="is_active" value="0" />
                        <Checkbox
                            id="is_active"
                            name="is_active"
                            value="1"
                            defaultChecked={account?.is_active ?? true}
                        />
                        <Label htmlFor="is_active">Active</Label>
                    </div>
                    <InputError message={errors.is_active} />

                    <DialogFooter>
                        <Button
                            type="button"
                            variant="outline"
                            onClick={() => onOpenChange(false)}
                        >
                            Cancel
                        </Button>
                        <Button type="submit" disabled={processing}>
                            {isEditing ? 'Save changes' : 'Create'}
                        </Button>
                    </DialogFooter>
                </>
            )}
        </Form>
    );
}

export function AccountFormDialog({
    open,
    onOpenChange,
    accountType,
    banks,
    account = null,
}: AccountFormDialogProps) {
    const isEditing = account !== null;
    const formKey = account?.id ?? 'create';

    return (
        <Dialog open={open} onOpenChange={onOpenChange}>
            <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-lg">
                <DialogHeader>
                    <DialogTitle>
                        {isEditing ? 'Edit Account' : 'Create Account'}
                    </DialogTitle>
                    <DialogDescription>
                        {isEditing
                            ? 'Update the account details below.'
                            : 'Fill in the details to create a new account.'}
                    </DialogDescription>
                </DialogHeader>

                {open ? (
                    <AccountFormDialogForm
                        key={formKey}
                        account={account}
                        accountType={accountType}
                        banks={banks}
                        onOpenChange={onOpenChange}
                    />
                ) : null}
            </DialogContent>
        </Dialog>
    );
}
