import { Link, useForm } from '@inertiajs/react';
import {
    Boxes,
    ClipboardCheck,
    DollarSign,
    Info,
    ListTree,
    Plus,
    Save,
    ShieldCheck,
    Trash2,
} from 'lucide-react';
import { useState } from 'react';
import { Callout, PageHeader, SectionCard } from '@/components/crm/page-header';
import { Field } from '@/components/crm/form-field';
import { NativeSelect } from '@/components/crm/native-select';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import {
    index as productsIndex,
    store,
    update,
} from '@/routes/warehouse/products';
import type {
    ProductDetail,
    ProductFormOptions,
    WarehouseAbilities,
} from '@/types';

type SpecificationRow = {
    key: string;
    value: string;
};

const textareaClassName =
    'border-input dark:bg-input/30 min-h-24 w-full rounded-md border bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]';

/**
 * The catalogue form, shared by create and edit so the two can never drift.
 *
 * Quantities are absent by design. Stock is only ever changed by a movement,
 * which writes the ledger row that explains it, so a product starts at zero
 * and its shelf count is a consequence of what the warehouse recorded rather
 * than a number typed into a settings page.
 */
export function ProductForm({
    product,
    options,
    can,
    mode,
}: {
    product?: ProductDetail;
    options: ProductFormOptions;
    can: WarehouseAbilities;
    mode: 'create' | 'edit';
}) {
    const [specifications, setSpecifications] = useState<SpecificationRow[]>(
        () =>
            product && product.specifications.length > 0
                ? product.specifications.map((specification) => ({
                      key: specification.label
                          .toLowerCase()
                          .replace(/[^a-z0-9]+/g, '_')
                          .replace(/^_|_$/g, ''),
                      value: specification.value,
                  }))
                : [{ key: '', value: '' }],
    );

    const form = useForm({
        sku: product?.sku ?? '',
        name: product?.name ?? '',
        category_id: product?.category?.id ? String(product.category.id) : '',
        brand: product?.brand ?? '',
        manufacturer: product?.manufacturer ?? '',
        model_number: product?.model_number ?? '',
        description: product?.description ?? '',
        unit: product?.unit ?? 'each',
        packaging_quantity: String(product?.packaging_quantity ?? 1),
        minimum_stock: String(product?.minimum_stock ?? 0),
        reorder_quantity: String(product?.reorder_quantity ?? 0),
        storage_location: product?.storage_location ?? '',
        tracks_serial_numbers: product?.tracks_serial_numbers ?? false,
        tracks_batches: product?.tracks_batches ?? false,
        warranty_months:
            product?.warranty_months === null ||
            product?.warranty_months === undefined
                ? ''
                : String(product.warranty_months),
        datasheet_url: product?.datasheet_url ?? '',
        source_url: product?.source_url ?? '',
        source_reviewed_on: product?.source_reviewed_on ?? '',
        verification_status: product?.verification.value ?? 'generic',
        purchase_cost: product?.purchase_cost ?? '',
        gst_treatment: product?.gst_treatment.value ?? 'gst_inclusive',
        is_active: product?.is_active ?? true,
    });

    const submit = () => {
        form.transform((data) => ({
            ...data,
            specifications: Object.fromEntries(
                specifications
                    .filter(
                        (row) =>
                            row.key.trim() !== '' && row.value.trim() !== '',
                    )
                    .map((row) => [row.key.trim(), row.value.trim()]),
            ),
        }));

        if (mode === 'create') {
            form.post(store().url);
        } else if (product) {
            form.put(update(product.id).url);
        }
    };

    const updateSpecification = (
        index: number,
        patch: Partial<SpecificationRow>,
    ) => {
        setSpecifications((rows) =>
            rows.map((row, position) =>
                position === index ? { ...row, ...patch } : row,
            ),
        );
    };

    return (
        <>
            <div className="flex flex-col gap-5">
                <PageHeader
                    eyebrow={
                        <>
                            <Boxes className="size-3.5 text-solar" />
                            <span>Product catalogue</span>
                        </>
                    }
                    title={
                        mode === 'create'
                            ? 'New product'
                            : `Edit ${product?.sku}`
                    }
                    description={
                        mode === 'create'
                            ? 'Add the product the company buys and installs. Stock is received afterwards, so the quantity starts at zero.'
                            : 'Correct the catalogue details. Quantities are changed by recording a stock movement, not here.'
                    }
                    actions={
                        <Button variant="outline" size="sm" asChild>
                            <Link href={productsIndex().url}>Cancel</Link>
                        </Button>
                    }
                />

                {mode === 'create' ? (
                    <Callout
                        tone="info"
                        icon={Info}
                        title="A catalogue line, not a shelf count"
                    >
                        A product starts with no stock. When goods arrive,
                        record a receipt from the product page; the ledger keeps
                        the quantity, the person and the reason together.
                    </Callout>
                ) : null}

                {mode === 'edit' ? (
                    <Callout
                        tone="warning"
                        icon={Info}
                        title="This page changes what the product is, not how many there are"
                    >
                        Use <strong>Record a movement</strong> on the product
                        page to receive, issue, reserve or correct stock. That
                        keeps every quantity change attached to a person and a
                        reason.
                    </Callout>
                ) : null}

                <form
                    onSubmit={(event) => {
                        event.preventDefault();
                        submit();
                    }}
                    className="flex flex-col gap-5"
                >
                    <SectionCard
                        title="Identity"
                        description="What the product is called and how the warehouse finds it."
                        icon={Boxes}
                        tone="solar"
                    >
                        <div className="grid gap-x-6 gap-y-4 md:grid-cols-2">
                            <Field
                                label="Stock code"
                                htmlFor="sku"
                                error={form.errors.sku}
                                hint="Unique, printed on the picking list"
                                required
                            >
                                <Input
                                    id="sku"
                                    value={form.data.sku}
                                    onChange={(event) =>
                                        form.setData('sku', event.target.value)
                                    }
                                    placeholder="PAN-MONO-400"
                                    className="font-mono uppercase"
                                    required
                                />
                            </Field>

                            <Field
                                label="Product name"
                                htmlFor="name"
                                error={form.errors.name}
                                required
                            >
                                <Input
                                    id="name"
                                    value={form.data.name}
                                    onChange={(event) =>
                                        form.setData('name', event.target.value)
                                    }
                                    placeholder="Jinko Tiger Neo 475 W panel"
                                    required
                                />
                            </Field>

                            <Field
                                label="Category"
                                htmlFor="category_id"
                                error={form.errors.category_id}
                            >
                                <NativeSelect
                                    id="category_id"
                                    value={form.data.category_id}
                                    onChange={(event) =>
                                        form.setData(
                                            'category_id',
                                            event.target.value,
                                        )
                                    }
                                >
                                    <option value="">Uncategorised</option>
                                    {options.categories.map((category) => (
                                        <option
                                            key={category.value}
                                            value={String(category.value)}
                                        >
                                            {category.label}
                                        </option>
                                    ))}
                                </NativeSelect>
                            </Field>

                            <Field
                                label="Storage location"
                                htmlFor="storage_location"
                                error={form.errors.storage_location}
                                hint="Bay, shelf or rack"
                            >
                                <Input
                                    id="storage_location"
                                    value={form.data.storage_location}
                                    onChange={(event) =>
                                        form.setData(
                                            'storage_location',
                                            event.target.value,
                                        )
                                    }
                                    placeholder="A-12-3"
                                />
                            </Field>

                            <Field
                                label="Brand"
                                htmlFor="brand"
                                error={form.errors.brand}
                            >
                                <Input
                                    id="brand"
                                    value={form.data.brand}
                                    onChange={(event) =>
                                        form.setData(
                                            'brand',
                                            event.target.value,
                                        )
                                    }
                                    placeholder="Jinko"
                                />
                            </Field>

                            <Field
                                label="Manufacturer"
                                htmlFor="manufacturer"
                                error={form.errors.manufacturer}
                                hint="Only when it differs from the brand"
                            >
                                <Input
                                    id="manufacturer"
                                    value={form.data.manufacturer}
                                    onChange={(event) =>
                                        form.setData(
                                            'manufacturer',
                                            event.target.value,
                                        )
                                    }
                                />
                            </Field>

                            <Field
                                label="Model number"
                                htmlFor="model_number"
                                error={form.errors.model_number}
                            >
                                <Input
                                    id="model_number"
                                    value={form.data.model_number}
                                    onChange={(event) =>
                                        form.setData(
                                            'model_number',
                                            event.target.value,
                                        )
                                    }
                                    placeholder="JKM475N-60HL4"
                                />
                            </Field>

                            <Field
                                label="How it is counted"
                                htmlFor="unit"
                                error={form.errors.unit}
                                required
                            >
                                <NativeSelect
                                    id="unit"
                                    value={form.data.unit}
                                    onChange={(event) =>
                                        form.setData('unit', event.target.value)
                                    }
                                >
                                    {options.units.map((unit) => (
                                        <option
                                            key={unit.value}
                                            value={unit.value}
                                        >
                                            {unit.label}
                                        </option>
                                    ))}
                                </NativeSelect>
                            </Field>

                            <Field
                                label="Description"
                                htmlFor="description"
                                error={form.errors.description}
                                className="md:col-span-2"
                            >
                                <textarea
                                    id="description"
                                    className={textareaClassName}
                                    value={form.data.description}
                                    onChange={(event) =>
                                        form.setData(
                                            'description',
                                            event.target.value,
                                        )
                                    }
                                    placeholder="What it is, what it suits, and anything the warehouse needs to know before picking it."
                                />
                            </Field>
                        </div>
                    </SectionCard>

                    <SectionCard
                        title="Specifications"
                        description="The fields that matter for this kind of product. A panel needs wattage and voltage; a clip needs the rail it fits."
                        icon={ListTree}
                        tone="info"
                    >
                        <div className="flex flex-col gap-2">
                            {specifications.map((row, index) => (
                                <div
                                    key={index}
                                    className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)_auto]"
                                >
                                    <Input
                                        value={row.key}
                                        onChange={(event) =>
                                            updateSpecification(index, {
                                                key: event.target.value,
                                            })
                                        }
                                        placeholder="Rated output"
                                        aria-label={`Specification ${index + 1} name`}
                                    />
                                    <Input
                                        value={row.value}
                                        onChange={(event) =>
                                            updateSpecification(index, {
                                                value: event.target.value,
                                            })
                                        }
                                        placeholder="475 W"
                                        aria-label={`Specification ${index + 1} value`}
                                    />
                                    <Button
                                        type="button"
                                        variant="ghost"
                                        size="icon"
                                        aria-label="Remove specification"
                                        onClick={() =>
                                            setSpecifications((rows) =>
                                                rows.length === 1
                                                    ? [{ key: '', value: '' }]
                                                    : rows.filter(
                                                          (_, position) =>
                                                              position !==
                                                              index,
                                                      ),
                                            )
                                        }
                                    >
                                        <Trash2 className="size-4" />
                                    </Button>
                                </div>
                            ))}

                            <div>
                                <Button
                                    type="button"
                                    variant="outline"
                                    size="sm"
                                    onClick={() =>
                                        setSpecifications((rows) => [
                                            ...rows,
                                            { key: '', value: '' },
                                        ])
                                    }
                                >
                                    <Plus className="size-4" />
                                    Add specification
                                </Button>
                            </div>
                        </div>
                    </SectionCard>

                    <SectionCard
                        title="Stock settings"
                        description="How this product is counted, when it needs reordering, and whether individual units are traced."
                        icon={ClipboardCheck}
                        tone="amber"
                    >
                        <div className="grid gap-x-6 gap-y-4 md:grid-cols-3">
                            <Field
                                label="Units per pack"
                                htmlFor="packaging_quantity"
                                error={form.errors.packaging_quantity}
                                hint="How many the supplier sells in"
                                required
                            >
                                <Input
                                    id="packaging_quantity"
                                    type="number"
                                    min={1}
                                    value={form.data.packaging_quantity}
                                    onChange={(event) =>
                                        form.setData(
                                            'packaging_quantity',
                                            event.target.value,
                                        )
                                    }
                                    required
                                />
                            </Field>

                            <Field
                                label="Minimum stock"
                                htmlFor="minimum_stock"
                                error={form.errors.minimum_stock}
                                hint="0 means no reorder point"
                                required
                            >
                                <Input
                                    id="minimum_stock"
                                    type="number"
                                    min={0}
                                    value={form.data.minimum_stock}
                                    onChange={(event) =>
                                        form.setData(
                                            'minimum_stock',
                                            event.target.value,
                                        )
                                    }
                                    required
                                />
                            </Field>

                            <Field
                                label="Reorder quantity"
                                htmlFor="reorder_quantity"
                                error={form.errors.reorder_quantity}
                                hint="Suggested when below the minimum"
                                required
                            >
                                <Input
                                    id="reorder_quantity"
                                    type="number"
                                    min={0}
                                    value={form.data.reorder_quantity}
                                    onChange={(event) =>
                                        form.setData(
                                            'reorder_quantity',
                                            event.target.value,
                                        )
                                    }
                                    required
                                />
                            </Field>

                            <Field
                                label="Warranty (months)"
                                htmlFor="warranty_months"
                                error={form.errors.warranty_months}
                            >
                                <Input
                                    id="warranty_months"
                                    type="number"
                                    min={0}
                                    value={form.data.warranty_months}
                                    onChange={(event) =>
                                        form.setData(
                                            'warranty_months',
                                            event.target.value,
                                        )
                                    }
                                />
                            </Field>

                            <label className="flex items-start gap-2.5 rounded-lg px-0.5 py-1 text-sm">
                                <Checkbox
                                    checked={form.data.tracks_serial_numbers}
                                    onCheckedChange={(checked) =>
                                        form.setData(
                                            'tracks_serial_numbers',
                                            checked === true,
                                        )
                                    }
                                    className="mt-0.5"
                                />
                                <span>
                                    <span className="font-medium">
                                        Serial numbers
                                    </span>
                                    <span className="block text-xs text-muted-foreground">
                                        Record a serial against each unit, for
                                        inverters and batteries.
                                    </span>
                                </span>
                            </label>

                            <label className="flex items-start gap-2.5 rounded-lg px-0.5 py-1 text-sm">
                                <Checkbox
                                    checked={form.data.tracks_batches}
                                    onCheckedChange={(checked) =>
                                        form.setData(
                                            'tracks_batches',
                                            checked === true,
                                        )
                                    }
                                    className="mt-0.5"
                                />
                                <span>
                                    <span className="font-medium">
                                        Batch numbers
                                    </span>
                                    <span className="block text-xs text-muted-foreground">
                                        Keep the supplier's batch with the stock
                                        for warranty claims.
                                    </span>
                                </span>
                            </label>
                        </div>
                    </SectionCard>

                    {can.viewCosts ? (
                        <SectionCard
                            title="Commercial"
                            description="What the company pays. Only roles with the stock cost permission can see or set this."
                            icon={DollarSign}
                            tone="success"
                        >
                            <div className="grid gap-x-6 gap-y-4 md:grid-cols-2">
                                <Field
                                    label="Purchase cost"
                                    htmlFor="purchase_cost"
                                    error={form.errors.purchase_cost}
                                    hint="Excluding or including GST, as chosen below"
                                >
                                    <Input
                                        id="purchase_cost"
                                        type="number"
                                        step="0.01"
                                        min={0}
                                        value={form.data.purchase_cost}
                                        onChange={(event) =>
                                            form.setData(
                                                'purchase_cost',
                                                event.target.value,
                                            )
                                        }
                                        placeholder="0.00"
                                    />
                                </Field>

                                <Field
                                    label="GST treatment"
                                    htmlFor="gst_treatment"
                                    error={form.errors.gst_treatment}
                                    required
                                >
                                    <NativeSelect
                                        id="gst_treatment"
                                        value={form.data.gst_treatment}
                                        onChange={(event) =>
                                            form.setData(
                                                'gst_treatment',
                                                event.target.value,
                                            )
                                        }
                                    >
                                        {options.gstTreatments.map(
                                            (treatment) => (
                                                <option
                                                    key={treatment.value}
                                                    value={treatment.value}
                                                >
                                                    {treatment.label}
                                                </option>
                                            ),
                                        )}
                                    </NativeSelect>
                                </Field>
                            </div>
                        </SectionCard>
                    ) : null}

                    <SectionCard
                        title="Provenance"
                        description="Where the details came from, so the catalogue never implies more certainty than it has."
                        icon={ShieldCheck}
                        tone="violet"
                    >
                        <div className="grid gap-x-6 gap-y-4 md:grid-cols-2">
                            <Field
                                label="Verification"
                                htmlFor="verification_status"
                                error={form.errors.verification_status}
                                hint="Set by whoever can vouch for it"
                                required
                            >
                                <NativeSelect
                                    id="verification_status"
                                    value={form.data.verification_status}
                                    onChange={(event) =>
                                        form.setData(
                                            'verification_status',
                                            event.target.value,
                                        )
                                    }
                                >
                                    {options.verifications.map(
                                        (verification) => (
                                            <option
                                                key={verification.value}
                                                value={verification.value}
                                            >
                                                {verification.label}
                                            </option>
                                        ),
                                    )}
                                </NativeSelect>
                            </Field>

                            <Field
                                label="Date reviewed"
                                htmlFor="source_reviewed_on"
                                error={form.errors.source_reviewed_on}
                            >
                                <Input
                                    id="source_reviewed_on"
                                    type="date"
                                    value={form.data.source_reviewed_on}
                                    onChange={(event) =>
                                        form.setData(
                                            'source_reviewed_on',
                                            event.target.value,
                                        )
                                    }
                                />
                            </Field>

                            <p className="rounded-lg bg-muted/40 px-3 py-2 text-xs leading-relaxed text-muted-foreground md:col-span-2">
                                {
                                    options.verifications.find(
                                        (verification) =>
                                            verification.value ===
                                            form.data.verification_status,
                                    )?.description
                                }
                            </p>

                            <Field
                                label="Source page"
                                htmlFor="source_url"
                                error={form.errors.source_url}
                                hint="Manufacturer or supplier page"
                            >
                                <Input
                                    id="source_url"
                                    type="url"
                                    value={form.data.source_url}
                                    onChange={(event) =>
                                        form.setData(
                                            'source_url',
                                            event.target.value,
                                        )
                                    }
                                    placeholder="https://"
                                />
                            </Field>

                            <Field
                                label="Datasheet"
                                htmlFor="datasheet_url"
                                error={form.errors.datasheet_url}
                                hint="PDF link, if there is one"
                            >
                                <Input
                                    id="datasheet_url"
                                    type="url"
                                    value={form.data.datasheet_url}
                                    onChange={(event) =>
                                        form.setData(
                                            'datasheet_url',
                                            event.target.value,
                                        )
                                    }
                                    placeholder="https://"
                                />
                            </Field>

                            <label className="flex items-start gap-2.5 py-1 text-sm md:col-span-2">
                                <Checkbox
                                    checked={form.data.is_active}
                                    onCheckedChange={(checked) =>
                                        form.setData(
                                            'is_active',
                                            checked === true,
                                        )
                                    }
                                    className="mt-0.5"
                                />
                                <span>
                                    <span className="font-medium">
                                        Active in the catalogue
                                    </span>
                                    <span className="block text-xs text-muted-foreground">
                                        Turning this off archives the product
                                        without deleting it, so old jobs and
                                        movements still name it.
                                    </span>
                                </span>
                            </label>
                        </div>
                    </SectionCard>

                    <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
                        <Button variant="outline" asChild>
                            <Link href={productsIndex().url}>Cancel</Link>
                        </Button>
                        <Button type="submit" disabled={form.processing}>
                            <Save className="size-4" />
                            {mode === 'create' ? 'Add product' : 'Save changes'}
                        </Button>
                    </div>
                </form>
            </div>
        </>
    );
}
