import { ConfirmDialog } from '@/components/dialogs';
import { DatePicker, PhoneNumberInput, RupiahInput } from '@/components/inputs';
import { InputError } from '@/components/ui';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import { formatCurrency } from '@/lib/utils';
import {
    index as invoiceIndex,
    print,
    update,
} from '@/routes/admin/manage/invoices';
import { Form, Head, Link } from '@inertiajs/react';
import { ArrowLeft, Plus, Printer, Trash2 } from 'lucide-react';
import { useCallback, useState } from 'react';
import { toast } from 'sonner';
import type { InvoiceForEdit } from './columns';

type ItemRow = {
    name: string;
    quantity: string;
    price: number;
};

type Props = {
    invoice: InvoiceForEdit;
    statusOptions: { value: string; label: string }[];
};

function toDateInputValue(date: Date | undefined) {
    return date ? date.toISOString().split('T')[0] : '';
}

function parseDateValue(value: string | null) {
    if (!value) {
        return undefined;
    }

    return new Date(value);
}

function emptyItem(): ItemRow {
    return { name: '', quantity: '1', price: 0 };
}

export default function InvoiceEdit({ invoice, statusOptions }: Props) {
    const [invoiceNumber, setInvoiceNumber] = useState(
        invoice.invoice_number,
    );
    const [customerName, setCustomerName] = useState(invoice.customer_name);
    const [date, setDate] = useState<Date | undefined>(
        parseDateValue(invoice.date),
    );
    const [dueDate, setDueDate] = useState<Date | undefined>(
        parseDateValue(invoice.due_date),
    );
    const [status, setStatus] = useState<string>(invoice.status);
    const [description, setDescription] = useState(
        invoice.description ?? '',
    );
    const [items, setItems] = useState<ItemRow[]>(() =>
        invoice.items.length > 0
            ? invoice.items.map((item) => ({
                name: item.name,
                quantity: String(item.quantity),
                price: item.price,
            }))
            : [emptyItem()],
    );

    const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
    const [deleteItemIndex, setDeleteItemIndex] = useState<number | null>(
        null,
    );

    const addItem = useCallback(() => {
        setItems((prev) => [...prev, emptyItem()]);
    }, []);

    const removeItem = useCallback((index: number) => {
        setItems((prev) => prev.filter((_, i) => i !== index));
    }, []);

    const confirmRemoveItem = useCallback(
        (index: number) => {
            if (items.length <= 1) {
                removeItem(index);
                return;
            }

            setDeleteItemIndex(index);
            setDeleteConfirmOpen(true);
        },
        [items.length, removeItem],
    );

    const updateItem = useCallback(
        (index: number, field: keyof ItemRow, value: string | number) => {
            setItems((prev) => {
                const updated = [...prev];
                (updated[index] as Record<string, unknown>)[field] = value;

                return updated;
            });
        },
        [],
    );

    const total = items.reduce(
        (sum, item) => sum + (parseInt(item.quantity, 10) || 0) * item.price,
        0,
    );

    function getPayload() {
        return {
            invoice_number: invoiceNumber,
            customer_name: customerName,
            date: toDateInputValue(date),
            due_date: dueDate ? toDateInputValue(dueDate) : null,
            status,
            description: description || null,
            items: items.map((item) => ({
                name: item.name,
                quantity: parseInt(item.quantity, 10) || 0,
                price: item.price,
            })),
        };
    }

    return (
        <>
            <Head title="Edit Invoice" />

            <div className="flex h-full flex-1 flex-col gap-6 overflow-x-auto p-4 md:p-6">
                <div className="flex items-center justify-between">
                    <h2 className="text-2xl font-semibold tracking-tight">
                        Edit Invoice
                    </h2>
                    <div className="flex items-center gap-2">
                        <Button asChild variant="outline">
                            <Link href={print.url(invoice.id)}>
                                <Printer className="h-4 w-4" />
                                Cetak PDF
                            </Link>
                        </Button>
                        <Button asChild variant="outline">
                            <Link href={invoiceIndex.url()}>
                                <ArrowLeft className="h-4 w-4" />
                                Kembali
                            </Link>
                        </Button>
                    </div>
                </div>

                <Form
                    action={update(invoice.id)}
                    transform={(data) => ({
                        ...data,
                        ...getPayload(),
                    })}
                    onError={() => {
                        toast.error(
                            'Ada data yang belum sesuai, silakan periksa kembali input Anda.',
                        );
                    }}
                >
                    {({ errors, processing }) => (
                        <div className="grid gap-6 md:grid-cols-3">
                            <div className="space-y-6 md:col-span-2">
                                <Card>
                                    <CardHeader>
                                        <CardTitle>Informasi Invoice</CardTitle>
                                    </CardHeader>
                                    <CardContent className="grid grid-cols-1 gap-4 md:grid-cols-3">
                                        <div className="grid gap-2">
                                            <Label htmlFor="invoice_number">
                                                Nomor Invoice{' '}
                                                <span className="text-destructive">
                                                    *
                                                </span>
                                            </Label>
                                            <Input
                                                id="invoice_number"
                                                value={invoiceNumber}
                                                onChange={(e) =>
                                                    setInvoiceNumber(
                                                        e.target.value,
                                                    )
                                                }
                                                placeholder="Masukkan nomor invoice"
                                            />
                                            <InputError
                                                message={errors.invoice_number}
                                            />
                                        </div>
                                        <div className="grid gap-2">
                                            <Label htmlFor="customer_name">
                                                Nama Pelanggan{' '}
                                                <span className="text-destructive">
                                                    *
                                                </span>
                                            </Label>
                                            <Input
                                                id="customer_name"
                                                value={customerName}
                                                onChange={(e) =>
                                                    setCustomerName(
                                                        e.target.value,
                                                    )
                                                }
                                                placeholder="Masukkan nama pelanggan"
                                            />
                                            <InputError
                                                message={errors.customer_name}
                                            />
                                        </div>
                                        <div className="grid gap-2">
                                            <Label htmlFor="customer_phone">
                                                No. Telepon Pelanggan
                                            </Label>
                                            <PhoneNumberInput
                                                name="customer_phone"
                                                defaultValue={
                                                    invoice.customer_phone
                                                }
                                                placeholder="0812 3456 7890"
                                            />
                                            <InputError
                                                message={
                                                    errors.customer_phone
                                                }
                                            />
                                        </div>
                                        <div className="grid gap-2 md:col-span-3">
                                            <Label htmlFor="customer_address">
                                                Alamat Pelanggan
                                            </Label>
                                            <Textarea
                                                id="customer_address"
                                                name="customer_address"
                                                defaultValue={
                                                    invoice.customer_address ??
                                                    ''
                                                }
                                                placeholder="Masukkan alamat pelanggan"
                                            />
                                            <InputError
                                                message={
                                                    errors.customer_address
                                                }
                                            />
                                        </div>
                                        <div className="grid grid-cols-2 gap-4 md:col-span-3">
                                            <div className="grid gap-2">
                                                <Label htmlFor="date">
                                                    Tanggal{' '}
                                                    <span className="text-destructive">
                                                        *
                                                    </span>
                                                </Label>
                                                <DatePicker
                                                    value={date}
                                                    onChange={setDate}
                                                    placeholder="Pilih tanggal"
                                                />
                                                <InputError
                                                    message={errors.date}
                                                />
                                            </div>
                                            <div className="grid gap-2">
                                                <Label htmlFor="due_date">
                                                    Jatuh Tempo
                                                </Label>
                                                <DatePicker
                                                    value={dueDate}
                                                    onChange={setDueDate}
                                                    placeholder="Pilih jatuh tempo"
                                                />
                                                <InputError
                                                    message={errors.due_date}
                                                />
                                            </div>
                                        </div>
                                    </CardContent>
                                </Card>

                                <Card>
                                    <CardHeader>
                                        <CardTitle>Item Invoice</CardTitle>
                                    </CardHeader>
                                    <CardContent className="space-y-4">
                                        {items.map((item, index) => (
                                            <div
                                                key={index}
                                                className="space-y-4 rounded-lg border p-4"
                                            >
                                                <div className="flex items-center justify-between">
                                                    <h4 className="font-medium">
                                                        Item {index + 1}
                                                    </h4>
                                                    {items.length > 1 && (
                                                        <Button
                                                            type="button"
                                                            variant="outline"
                                                            size="icon"
                                                            onClick={() =>
                                                                confirmRemoveItem(
                                                                    index,
                                                                )
                                                            }
                                                        >
                                                            <Trash2 className="h-4 w-4 text-destructive" />
                                                        </Button>
                                                    )}
                                                </div>
                                                <div className="grid grid-cols-1 gap-4 md:grid-cols-3">
                                                    <div className="grid gap-2 md:col-span-1">
                                                        <Label>
                                                            Nama Item{' '}
                                                            <span className="text-destructive">
                                                                *
                                                            </span>
                                                        </Label>
                                                        <Input
                                                            value={item.name}
                                                            onChange={(e) =>
                                                                updateItem(
                                                                    index,
                                                                    'name',
                                                                    e.target
                                                                        .value,
                                                                )
                                                            }
                                                            placeholder="Contoh: Jasa Cutting"
                                                        />
                                                        <InputError
                                                            message={
                                                                errors[
                                                                `items.${index}.name`
                                                                ]
                                                            }
                                                        />
                                                    </div>
                                                    <div className="grid gap-2">
                                                        <Label>
                                                            Jumlah{' '}
                                                            <span className="text-destructive">
                                                                *
                                                            </span>
                                                        </Label>
                                                        <Input
                                                            type="text"
                                                            inputMode="numeric"
                                                            value={
                                                                item.quantity
                                                            }
                                                            onChange={(e) =>
                                                                updateItem(
                                                                    index,
                                                                    'quantity',
                                                                    e.target
                                                                        .value,
                                                                )
                                                            }
                                                        />
                                                        <InputError
                                                            message={
                                                                errors[
                                                                `items.${index}.quantity`
                                                                ]
                                                            }
                                                        />
                                                    </div>
                                                    <div className="grid gap-2">
                                                        <Label>
                                                            Harga Satuan{' '}
                                                            <span className="text-destructive">
                                                                *
                                                            </span>
                                                        </Label>
                                                        <RupiahInput
                                                            value={item.price}
                                                            onValueChange={(
                                                                val,
                                                            ) =>
                                                                updateItem(
                                                                    index,
                                                                    'price',
                                                                    val,
                                                                )
                                                            }
                                                        />
                                                        <InputError
                                                            message={
                                                                errors[
                                                                `items.${index}.price`
                                                                ]
                                                            }
                                                        />
                                                    </div>
                                                </div>
                                                <div className="text-right text-sm text-muted-foreground">
                                                    Subtotal:{' '}
                                                    <span className="font-medium text-foreground">
                                                        {formatCurrency(
                                                            (parseInt(
                                                                item.quantity,
                                                                10,
                                                            ) || 0) *
                                                            item.price,
                                                        )}
                                                    </span>
                                                </div>
                                            </div>
                                        ))}

                                        <Button
                                            type="button"
                                            variant="outline"
                                            onClick={addItem}
                                        >
                                            <Plus className="h-4 w-4" />
                                            Tambah Item
                                        </Button>
                                        <InputError message={errors.items} />
                                    </CardContent>
                                </Card>
                            </div>

                            <div className="space-y-6 md:col-span-1">
                                <Card className="sticky top-6">
                                    <CardHeader>
                                        <CardTitle>Ringkasan</CardTitle>
                                    </CardHeader>
                                    <CardContent className="space-y-4">
                                        <div className="grid gap-2">
                                            <Label>
                                                Status{' '}
                                                <span className="text-destructive">
                                                    *
                                                </span>
                                            </Label>
                                            <Select
                                                value={status}
                                                onValueChange={setStatus}
                                            >
                                                <SelectTrigger className="w-full">
                                                    <SelectValue placeholder="Pilih status" />
                                                </SelectTrigger>
                                                <SelectContent>
                                                    {statusOptions.map(
                                                        (opt) => (
                                                            <SelectItem
                                                                key={
                                                                    opt.value
                                                                }
                                                                value={
                                                                    opt.value
                                                                }
                                                            >
                                                                {opt.label}
                                                            </SelectItem>
                                                        ),
                                                    )}
                                                </SelectContent>
                                            </Select>
                                            <InputError
                                                message={errors.status}
                                            />
                                        </div>

                                        <div className="grid gap-2">
                                            <Label htmlFor="description">
                                                Keterangan
                                            </Label>
                                            <Textarea
                                                id="description"
                                                value={description}
                                                onChange={(e) =>
                                                    setDescription(
                                                        e.target.value,
                                                    )
                                                }
                                                placeholder="Masukkan keterangan"
                                            />
                                            <InputError
                                                message={errors.description}
                                            />
                                        </div>

                                        <div className="border-t pt-2">
                                            <div className="flex items-center justify-between text-sm font-semibold">
                                                <span>Total</span>
                                                <span>
                                                    {formatCurrency(total)}
                                                </span>
                                            </div>
                                        </div>

                                        <Button
                                            type="submit"
                                            className="w-full"
                                            disabled={
                                                processing ||
                                                !invoiceNumber ||
                                                !customerName ||
                                                !date ||
                                                items.length === 0 ||
                                                items.some((i) => !i.name)
                                            }
                                        >
                                            {processing
                                                ? 'Menyimpan...'
                                                : 'Simpan'}
                                        </Button>
                                    </CardContent>
                                </Card>
                            </div>
                        </div>
                    )}
                </Form>

                <ConfirmDialog
                    open={deleteConfirmOpen}
                    onOpenChange={(open) => {
                        if (!open) {
                            setDeleteConfirmOpen(false);
                            setDeleteItemIndex(null);
                        }
                    }}
                    title="Hapus Item"
                    description="Apakah Anda yakin ingin menghapus item ini?"
                    confirmLabel="Hapus"
                    variant="destructive"
                    onConfirm={() => {
                        if (deleteItemIndex !== null) {
                            removeItem(deleteItemIndex);
                        }

                        setDeleteConfirmOpen(false);
                        setDeleteItemIndex(null);
                    }}
                />
            </div>
        </>
    );
}
