import { Link, usePage } from '@inertiajs/react';
import type { InertiaFormProps } from '@inertiajs/react';
import type { AppPageProps } from '@/types';

export type SelectOption = {
    value: string;
    label: string;
};

export type CustomerOption = {
    id: number;
    name: string;
    email: string;
    phone: string | null;
    address_line1: string | null;
    address_line2: string | null;
    city: string | null;
    postal_code: string | null;
    country: string | null;
};

export type ProductOption = {
    id: number;
    name: string;
    slug: string;
    sku: string | null;
    price_minor: number;
};

export type OrderItemForm = {
    product_id: string;
    product_name: string;
    product_slug: string;
    sku: string;
    quantity: string;
    unit_price_minor: string;
    line_total_minor: string;
};

export type OrderFormData = {
    user_id: string;
    order_number: string;
    status: string;
    currency: string;
    total_minor: string;
    customer_name: string;
    customer_email: string;
    customer_phone: string;
    address_line1: string;
    address_line2: string;
    city: string;
    postal_code: string;
    country: string;
    notes: string;
    placed_at: string;
    items: OrderItemForm[];
};

type OrderFormProps = {
    title: string;
    submitLabel: string;
    backHref: string;
    form: InertiaFormProps<OrderFormData>;
    statusOptions: SelectOption[];
    customerOptions: CustomerOption[];
    productOptions: ProductOption[];
    onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
};

export function OrderForm({
    title,
    submitLabel,
    backHref,
    form,
    statusOptions,
    customerOptions,
    productOptions,
    onSubmit,
}: OrderFormProps) {
    const { config } = usePage<AppPageProps>().props;

    const selectCustomer = (customerId: string) => {
        const customer = customerOptions.find(
            (option) => String(option.id) === customerId,
        );

        if (customer === undefined) {
            form.setData('user_id', '');

            return;
        }

        form.setData({
            ...form.data,
            user_id: customerId,
            customer_name: customer.name,
            customer_email: customer.email,
            customer_phone: customer.phone || '',
            address_line1: customer.address_line1 || '',
            address_line2: customer.address_line2 || '',
            city: customer.city || '',
            postal_code: customer.postal_code || '',
            country: customer.country || '',
        });
    };

    const updateItem = (
        index: number,
        field: keyof OrderItemForm,
        value: string,
    ) => {
        const items = [...form.data.items];
        const item = {
            ...items[index],
            [field]: value,
        };

        if (field === 'quantity' || field === 'unit_price_minor') {
            item.line_total_minor = String(
                calculateLineTotal(item.quantity, item.unit_price_minor),
            );
        }

        items[index] = item;
        form.setData('items', items);
    };

    const selectProduct = (index: number, productId: string) => {
        const items = [...form.data.items];
        const current = items[index];

        if (current === undefined) {
            return;
        }

        const product = productOptions.find(
            (option) => String(option.id) === productId,
        );

        if (product === undefined) {
            items[index] = {
                ...current,
                product_id: '',
            };
            form.setData('items', items);

            return;
        }

        const quantity = current.quantity || '1';
        items[index] = {
            ...current,
            product_id: productId,
            product_name: product.name,
            product_slug: product.slug,
            sku: product.sku || '',
            quantity,
            unit_price_minor: String(product.price_minor),
            line_total_minor: String(
                calculateLineTotal(quantity, String(product.price_minor)),
            ),
        };

        form.setData('items', items);
    };

    const addItem = () => {
        form.setData('items', [...form.data.items, blankOrderItem()]);
    };

    const removeItem = (index: number) => {
        if (form.data.items.length === 1) {
            return;
        }

        form.setData(
            'items',
            form.data.items.filter((_, itemIndex) => itemIndex !== index),
        );
    };

    const calculatedTotal = form.data.items.reduce(
        (total, item) =>
            total +
            (toNumber(item.line_total_minor) ||
                calculateLineTotal(item.quantity, item.unit_price_minor)),
        0,
    );

    return (
        <div className="space-y-5">
            <div className="flex flex-wrap items-center justify-between gap-3">
                <h1 className="text-2xl font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                    {title}
                </h1>
                <Link
                    href={backHref}
                    className="text-sm font-medium text-slate-600 hover:text-[#0a1530] dark:text-[#d7c7ff] dark:hover:text-[#efe8ff]"
                >
                    Back
                </Link>
            </div>

            <form onSubmit={onSubmit} className="space-y-5">
                <section className="space-y-4 rounded-xl border border-slate-200 bg-white p-4 dark:border-[#3c2b68] dark:bg-[#211740]">
                    <h2 className="text-base font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                        Order
                    </h2>
                    <div className="grid gap-4 md:grid-cols-4">
                        <Field
                            label="Order Number"
                            error={form.errors.order_number}
                        >
                            <input
                                value={form.data.order_number}
                                onChange={(event) =>
                                    form.setData(
                                        'order_number',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                                placeholder="Generated if blank"
                            />
                        </Field>
                        <Field label="Status" error={form.errors.status}>
                            <select
                                value={form.data.status}
                                onChange={(event) =>
                                    form.setData('status', event.target.value)
                                }
                                className={inputClassName}
                                required
                            >
                                {statusOptions.map((option) => (
                                    <option
                                        key={option.value}
                                        value={option.value}
                                    >
                                        {option.label}
                                    </option>
                                ))}
                            </select>
                        </Field>
                        <Field label="Currency" error={form.errors.currency}>
                            <input
                                value={form.data.currency}
                                onChange={(event) =>
                                    form.setData('currency', event.target.value)
                                }
                                className={inputClassName}
                                required
                            />
                        </Field>
                        <Field label="Placed At" error={form.errors.placed_at}>
                            <input
                                type="datetime-local"
                                value={form.data.placed_at}
                                onChange={(event) =>
                                    form.setData(
                                        'placed_at',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                            />
                        </Field>
                    </div>
                </section>

                <section className="space-y-4 rounded-xl border border-slate-200 bg-white p-4 dark:border-[#3c2b68] dark:bg-[#211740]">
                    <h2 className="text-base font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                        Customer
                    </h2>
                    <Field label="Saved Customer" error={form.errors.user_id}>
                        <select
                            value={form.data.user_id}
                            onChange={(event) =>
                                selectCustomer(event.target.value)
                            }
                            className={inputClassName}
                        >
                            <option value="">Guest or manual customer</option>
                            {customerOptions.map((customer) => (
                                <option key={customer.id} value={customer.id}>
                                    {customer.name} / {customer.email}
                                </option>
                            ))}
                        </select>
                    </Field>
                    <div className="grid gap-4 md:grid-cols-3">
                        <Field
                            label="Customer Name"
                            error={form.errors.customer_name}
                        >
                            <input
                                value={form.data.customer_name}
                                onChange={(event) =>
                                    form.setData(
                                        'customer_name',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                                required
                            />
                        </Field>
                        <Field
                            label="Customer Email"
                            error={form.errors.customer_email}
                        >
                            <input
                                type="email"
                                value={form.data.customer_email}
                                onChange={(event) =>
                                    form.setData(
                                        'customer_email',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                                required
                            />
                        </Field>
                        <Field
                            label="Customer Phone"
                            error={form.errors.customer_phone}
                        >
                            <input
                                value={form.data.customer_phone}
                                onChange={(event) =>
                                    form.setData(
                                        'customer_phone',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                            />
                        </Field>
                    </div>
                    <div className="grid gap-4 md:grid-cols-2">
                        <Field
                            label="Address Line 1"
                            error={form.errors.address_line1}
                        >
                            <input
                                value={form.data.address_line1}
                                onChange={(event) =>
                                    form.setData(
                                        'address_line1',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                                required
                            />
                        </Field>
                        <Field
                            label="Address Line 2"
                            error={form.errors.address_line2}
                        >
                            <input
                                value={form.data.address_line2}
                                onChange={(event) =>
                                    form.setData(
                                        'address_line2',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                            />
                        </Field>
                    </div>
                    <div className="grid gap-4 md:grid-cols-3">
                        <Field label="City" error={form.errors.city}>
                            <input
                                value={form.data.city}
                                onChange={(event) =>
                                    form.setData('city', event.target.value)
                                }
                                className={inputClassName}
                                required
                            />
                        </Field>
                        <Field
                            label="Postal Code"
                            error={form.errors.postal_code}
                        >
                            <input
                                value={form.data.postal_code}
                                onChange={(event) =>
                                    form.setData(
                                        'postal_code',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                                required
                            />
                        </Field>
                        <Field label="Country" error={form.errors.country}>
                            <input
                                value={form.data.country}
                                onChange={(event) =>
                                    form.setData('country', event.target.value)
                                }
                                className={inputClassName}
                                required
                            />
                        </Field>
                    </div>
                    <Field label="Notes" error={form.errors.notes}>
                        <textarea
                            value={form.data.notes}
                            onChange={(event) =>
                                form.setData('notes', event.target.value)
                            }
                            rows={3}
                            className={inputClassName}
                        />
                    </Field>
                </section>

                <section className="space-y-4 rounded-xl border border-slate-200 bg-white p-4 dark:border-[#3c2b68] dark:bg-[#211740]">
                    <div className="flex flex-wrap items-center justify-between gap-3">
                        <h2 className="text-base font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                            Items
                        </h2>
                        <button
                            type="button"
                            onClick={addItem}
                            className="rounded-lg border border-slate-300 px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-100 dark:border-[#4a3a78] dark:text-[#e5dcff] dark:hover:bg-[#2a1d50]"
                        >
                            Add Item
                        </button>
                    </div>

                    <div className="space-y-4">
                        {form.data.items.map((item, index) => (
                            <article
                                key={index}
                                className="space-y-3 rounded-lg border border-slate-200 p-3 dark:border-[#3c2b68]"
                            >
                                <div className="flex items-center justify-between gap-3">
                                    <p className="text-sm font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                                        Item {index + 1}
                                    </p>
                                    <button
                                        type="button"
                                        onClick={() => removeItem(index)}
                                        disabled={form.data.items.length === 1}
                                        className="rounded-md border border-rose-200 px-2.5 py-1 text-xs font-medium text-rose-700 hover:bg-rose-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-rose-400/40 dark:text-rose-200 dark:hover:bg-rose-400/10"
                                    >
                                        Remove
                                    </button>
                                </div>

                                <Field
                                    label="Catalog Product"
                                    error={
                                        form.errors[`items.${index}.product_id`]
                                    }
                                >
                                    <select
                                        value={item.product_id}
                                        onChange={(event) =>
                                            selectProduct(
                                                index,
                                                event.target.value,
                                            )
                                        }
                                        className={inputClassName}
                                    >
                                        <option value="">
                                            Manual external item
                                        </option>
                                        {productOptions.map((product) => (
                                            <option
                                                key={product.id}
                                                value={product.id}
                                            >
                                                {product.sku
                                                    ? `${product.sku} / `
                                                    : ''}
                                                {product.name}
                                            </option>
                                        ))}
                                    </select>
                                </Field>

                                <div className="grid gap-4 md:grid-cols-3">
                                    <Field
                                        label="Product Name"
                                        error={
                                            form.errors[
                                                `items.${index}.product_name`
                                            ]
                                        }
                                    >
                                        <input
                                            value={item.product_name}
                                            onChange={(event) =>
                                                updateItem(
                                                    index,
                                                    'product_name',
                                                    event.target.value,
                                                )
                                            }
                                            className={inputClassName}
                                            required
                                        />
                                    </Field>
                                    <Field
                                        label="SKU"
                                        error={
                                            form.errors[`items.${index}.sku`]
                                        }
                                    >
                                        <input
                                            value={item.sku}
                                            onChange={(event) =>
                                                updateItem(
                                                    index,
                                                    'sku',
                                                    event.target.value,
                                                )
                                            }
                                            className={inputClassName}
                                        />
                                    </Field>
                                    <Field
                                        label="Product Slug"
                                        error={
                                            form.errors[
                                                `items.${index}.product_slug`
                                            ]
                                        }
                                    >
                                        <input
                                            value={item.product_slug}
                                            onChange={(event) =>
                                                updateItem(
                                                    index,
                                                    'product_slug',
                                                    event.target.value,
                                                )
                                            }
                                            className={inputClassName}
                                        />
                                    </Field>
                                </div>

                                <div className="grid gap-4 md:grid-cols-3">
                                    <Field
                                        label="Quantity"
                                        error={
                                            form.errors[
                                                `items.${index}.quantity`
                                            ]
                                        }
                                    >
                                        <input
                                            type="number"
                                            min={1}
                                            value={item.quantity}
                                            onChange={(event) =>
                                                updateItem(
                                                    index,
                                                    'quantity',
                                                    event.target.value,
                                                )
                                            }
                                            className={inputClassName}
                                            required
                                        />
                                    </Field>
                                    <Field
                                        label="Unit Price Minor"
                                        error={
                                            form.errors[
                                                `items.${index}.unit_price_minor`
                                            ]
                                        }
                                    >
                                        <input
                                            type="number"
                                            min={0}
                                            value={item.unit_price_minor}
                                            onChange={(event) =>
                                                updateItem(
                                                    index,
                                                    'unit_price_minor',
                                                    event.target.value,
                                                )
                                            }
                                            className={inputClassName}
                                            required
                                        />
                                    </Field>
                                    <Field
                                        label="Line Total Minor"
                                        error={
                                            form.errors[
                                                `items.${index}.line_total_minor`
                                            ]
                                        }
                                    >
                                        <input
                                            type="number"
                                            min={0}
                                            value={item.line_total_minor}
                                            onChange={(event) =>
                                                updateItem(
                                                    index,
                                                    'line_total_minor',
                                                    event.target.value,
                                                )
                                            }
                                            className={inputClassName}
                                        />
                                    </Field>
                                </div>
                            </article>
                        ))}
                    </div>
                </section>

                <section className="rounded-xl border border-slate-200 bg-slate-50/80 p-4 dark:border-[#3c2b68] dark:bg-[#2a1d50]/40">
                    <div className="grid gap-4 md:grid-cols-[1fr_240px_auto] md:items-end">
                        <div className="text-sm text-slate-700 dark:text-[#e5dcff]">
                            <p className="font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                                Calculated subtotal:{' '}
                                {formatMoney(
                                    calculatedTotal,
                                    form.data.currency ||
                                        config.default_currency,
                                )}
                            </p>
                            <p className="mt-1 text-xs text-slate-500 dark:text-[#bcaee6]">
                                Leave total blank to use the calculated
                                subtotal.
                            </p>
                        </div>
                        <Field
                            label="Total Minor"
                            error={form.errors.total_minor}
                        >
                            <input
                                type="number"
                                min={0}
                                value={form.data.total_minor}
                                onChange={(event) =>
                                    form.setData(
                                        'total_minor',
                                        event.target.value,
                                    )
                                }
                                className={inputClassName}
                                placeholder={String(calculatedTotal)}
                            />
                        </Field>
                        <button
                            type="submit"
                            disabled={form.processing}
                            className="w-full rounded-lg bg-[#0b7285] px-4 py-2 text-sm font-semibold text-white hover:bg-[#095f6f] disabled:opacity-50 md:w-auto dark:bg-[#7c3aed] dark:hover:bg-[#8b5cf6]"
                        >
                            {form.processing ? 'Saving...' : submitLabel}
                        </button>
                    </div>
                </section>
            </form>
        </div>
    );
}

export function blankOrderItem(): OrderItemForm {
    return {
        product_id: '',
        product_name: '',
        product_slug: '',
        sku: '',
        quantity: '1',
        unit_price_minor: '0',
        line_total_minor: '0',
    };
}

export function normalizeOrderForm(data: OrderFormData): object {
    return {
        ...data,
        user_id: data.user_id === '' ? null : Number(data.user_id),
        order_number: data.order_number === '' ? null : data.order_number,
        total_minor:
            data.total_minor === ''
                ? null
                : Math.max(0, Number(data.total_minor)),
        customer_phone: data.customer_phone === '' ? null : data.customer_phone,
        address_line2: data.address_line2 === '' ? null : data.address_line2,
        notes: data.notes === '' ? null : data.notes,
        placed_at: data.placed_at === '' ? null : data.placed_at,
        items: data.items.map((item) => ({
            product_id: item.product_id === '' ? null : Number(item.product_id),
            product_name: item.product_name === '' ? null : item.product_name,
            product_slug: item.product_slug === '' ? null : item.product_slug,
            sku: item.sku === '' ? null : item.sku,
            quantity: Math.max(1, Number(item.quantity || 1)),
            unit_price_minor: Math.max(0, Number(item.unit_price_minor || 0)),
            line_total_minor:
                item.line_total_minor === ''
                    ? null
                    : Math.max(0, Number(item.line_total_minor)),
        })),
    };
}

export function toDateTimeInputValue(value: string | null): string {
    if (value === null || value === '') {
        return '';
    }

    return value.replace(' ', 'T').slice(0, 16);
}

function Field({
    label,
    error,
    children,
}: {
    label: string;
    error?: string;
    children: React.ReactNode;
}) {
    return (
        <div>
            <label className="block text-sm font-medium text-[#0a1530] dark:text-[#e5dcff]">
                {label}
            </label>
            <div className="mt-1">{children}</div>
            {error ? (
                <p className="mt-1 text-xs text-rose-600">{error}</p>
            ) : null}
        </div>
    );
}

function calculateLineTotal(quantity: string, unitPriceMinor: string): number {
    return (
        Math.max(1, Number(quantity || 1)) *
        Math.max(0, Number(unitPriceMinor || 0))
    );
}

function toNumber(value: string): number {
    return Number(value || 0);
}

function formatMoney(minor: number, currency: string): string {
    return `${currency} ${(minor / 100).toFixed(2)}`;
}

const inputClassName =
    'w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]';
