import React, { useEffect, useState } from 'react';
import { ScrollArea } from '../../ui/scroll-area';
import { Input } from '../../ui/input';
import { Button } from '../../ui/button';
import { Label } from '../../ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '../../ui/select';
import { Switch } from '../../ui/switch';
import type {
  LabelTemplate,
  LabelElement,
  Unit,
  Rotation,
  Border,
  NutritionExtraItem,
} from '../../../types/labelTemplate';
import { canonicalElementType, isBlankSpaceElement, NUTRITION_FIXED_ITEMS } from '../../../types/labelTemplate';
import type { LabelMultipleOptionDto } from '../../../types/labelMultipleOption';
import { getLabelMultipleOptions } from '../../../services/labelMultipleOptionService';
import { Checkbox } from '../../ui/checkbox';
import { Trash2 } from 'lucide-react';

const DATE_FORMAT_OPTIONS = [
  'DD/MM/YYYY',
  'MM/DD/YYYY',
  'DD/MM/YY',
  'MM/DD/YY',
  'MM/YY',
  'MM/DD',
  'MM',
  'DD',
  'YY',
  'FULLY DAY(WEDNESDAY)',
  'DAY (WED)',
  'MONTH (DECEMBER)',
  'YEAR (2025)',
  'DD MONTH YEAR (25 DECEMBER 2025)',
] as const;
const DATETIME_DEFAULT_FORMAT = 'YYYY-MM-DD HH:mm';

const DURATION_FORMAT_OPTIONS = [
  'Minutes',
  'Hours',
  'Days',
  'Weeks',
  'Months (30 Day)',
  'Years',
] as const;

interface PropertiesPanelProps {
  template: LabelTemplate;
  selectedElement: LabelElement | null;
  onTemplateChange: (patch: Partial<LabelTemplate>) => void;
  onElementChange: (id: string, patch: Partial<LabelElement>) => void;
  onDeleteElement?: (id: string) => void;
  /** 编辑已有模板时禁止修改 Template Code */
  readOnlyTemplateCode?: boolean;
}

export function PropertiesPanel({
  template,
  selectedElement,
  onTemplateChange,
  onElementChange,
  onDeleteElement,
  readOnlyTemplateCode = false,
}: PropertiesPanelProps) {
  void template;
  void onTemplateChange;
  void readOnlyTemplateCode;
  if (selectedElement) {
    const isBlankElement = isBlankSpaceElement(selectedElement);
    return (
      <div className="w-72 shrink-0 border-l border-gray-200 bg-white flex flex-col h-full">
        <div className="px-3 py-2 border-b border-gray-200 font-semibold text-gray-800">
          Properties (Element)
        </div>
        <ScrollArea className="flex-1">
          <div className="p-3 space-y-3">
            <div className="grid grid-cols-2 gap-2">
              <div>
                <Label className="text-xs">X</Label>
                <Input
                  type="number"
                  value={selectedElement.x}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      x: Number(e.target.value) || 0,
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
              <div>
                <Label className="text-xs">Y</Label>
                <Input
                  type="number"
                  value={selectedElement.y}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      y: Number(e.target.value) || 0,
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
            </div>
            <div className="grid grid-cols-2 gap-2">
              <div>
                <Label className="text-xs">Width</Label>
                <Input
                  type="number"
                  value={selectedElement.width}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      width: Math.max(1, Number(e.target.value) || 0),
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
              <div>
                <Label className="text-xs">Height</Label>
                <Input
                  type="number"
                  value={selectedElement.height}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      height: Math.max(1, Number(e.target.value) || 0),
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
            </div>
            {!isBlankElement ? (
              <div>
                <Label className="text-xs">Rotation</Label>
                <Select
                  value={selectedElement.rotation}
                  onValueChange={(v: Rotation) =>
                    onElementChange(selectedElement.id, { rotation: v })
                  }
                >
                  <SelectTrigger className="h-8 text-sm">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="horizontal">horizontal</SelectItem>
                    <SelectItem value="vertical">vertical</SelectItem>
                  </SelectContent>
                </Select>
              </div>
            ) : null}
            {!isBlankElement ? (
              <div>
                <Label className="text-xs">Border</Label>
                <Select
                  value={selectedElement.border}
                  onValueChange={(v: Border) =>
                    onElementChange(selectedElement.id, { border: v })
                  }
                >
                  <SelectTrigger className="h-8 text-sm">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="none">none</SelectItem>
                    <SelectItem value="line">line</SelectItem>
                    <SelectItem value="dotted">dotted</SelectItem>
                  </SelectContent>
                </Select>
              </div>
            ) : null}
            <div>
              <Label className="text-xs">Element name</Label>
              <Input
                value={(selectedElement.elementName ?? "").trim()}
                onChange={(e) =>
                  onElementChange(selectedElement.id, {
                    elementName: e.target.value,
                  })
                }
                className="h-8 text-sm mt-1"
                placeholder="e.g. text1"
              />
              <p className="text-[10px] text-gray-400 mt-1">
                Required for save; used as data-entry column header (elementName).
              </p>
            </div>
            <ElementConfigFields
              element={selectedElement}
              onChange={(config) =>
                onElementChange(selectedElement.id, { config: { ...selectedElement.config, ...config } })
              }
            />
            {onDeleteElement && (
              <div className="pt-4 border-t border-gray-100">
                <Button
                  variant="destructive"
                  className="w-full gap-2"
                  onClick={() => onDeleteElement(selectedElement.id)}
                >
                  <Trash2 className="h-4 w-4 shrink-0" />
                  Delete Element
                </Button>
              </div>
            )}
          </div>
        </ScrollArea>
      </div>
    );
  }

  return (
    <div className="w-72 shrink-0 border-l border-gray-200 bg-white flex flex-col h-full">
      <div className="px-3 py-2 border-b border-gray-200 font-semibold text-gray-800">
        Properties (Element)
      </div>
      <ScrollArea className="flex-1">
        <div className="p-3">
          <div className="rounded-md border border-blue-100 bg-blue-50/50 p-3 text-xs text-blue-900">
            Select an element on the canvas to edit its properties.
          </div>
        </div>
      </ScrollArea>
    </div>
  );
}

const MULTIPLE_OPTION_NONE = '__none__';

/** 绑定「Multiple Options」页维护的字典：先选字典，再在该字典的值列表中多选 */
function MultipleOptionsDictionaryFields({
  cfg,
  onPatch,
}: {
  cfg: Record<string, unknown>;
  onPatch: (patch: Record<string, unknown>) => void;
}) {
  const [rows, setRows] = useState<LabelMultipleOptionDto[]>([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    getLabelMultipleOptions({ skipCount: 1, maxResultCount: 500 })
      .then((res) => {
        if (!cancelled) setRows(res.items ?? []);
      })
      .catch(() => {
        if (!cancelled) setRows([]);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, []);

  const selectedId = ((cfg.multipleOptionId as string) ?? '').trim();
  const selectedVals = Array.isArray(cfg.selectedOptionValues)
    ? (cfg.selectedOptionValues as string[])
    : [];
  const active = rows.find((r) => r.id === selectedId);
  const valueList = active?.optionValuesJson ?? [];

  /** 从服务端拉到的字典列表就绪后，为已绑定 id 的旧模板补上 multipleOptionName，画布才能显示「名称:」前缀 */
  useEffect(() => {
    if (!selectedId || rows.length === 0) return;
    const row = rows.find((r) => r.id === selectedId);
    const name = String(row?.optionName ?? '').trim();
    if (!row || !name) return;
    const current = String(cfg.multipleOptionName ?? '').trim();
    if (name !== current) {
      onPatch({ multipleOptionName: name });
    }
  }, [selectedId, rows, cfg.multipleOptionName, onPatch]);

  const selectValue = selectedId ? selectedId : MULTIPLE_OPTION_NONE;

  return (
    <>
      <div>
        <Label className="text-xs">Option dictionary</Label>
        <Select
          value={selectValue}
          onValueChange={(id) => {
            if (id === MULTIPLE_OPTION_NONE) {
              onPatch({ multipleOptionId: '', multipleOptionName: '', selectedOptionValues: [] });
              return;
            }
            const next = rows.find((r) => r.id === id);
            const allowed = new Set(next?.optionValuesJson ?? []);
            const filtered = selectedVals.filter((v) => allowed.has(v));
            const optName = String(next?.optionName ?? next?.optionCode ?? '').trim();
            onPatch({
              multipleOptionId: id,
              multipleOptionName: optName,
              selectedOptionValues: filtered,
            });
          }}
          disabled={loading}
        >
          <SelectTrigger className="h-8 text-sm mt-1">
            <SelectValue placeholder={loading ? 'Loading…' : 'Select from Multiple Options'} />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value={MULTIPLE_OPTION_NONE}>— None —</SelectItem>
            {rows.map((o) => (
              <SelectItem key={o.id} value={o.id}>
                {(o.optionName ?? o.optionCode ?? o.id) as string}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
        <p className="text-[10px] text-gray-400 mt-1">
          Data comes from the Multiple Options tab (label-multiple-option list).
        </p>
      </div>
      {active && valueList.length > 0 ? (
        <div>
          <Label className="text-xs">Values (multi-select)</Label>
          <div className="mt-1 max-h-44 overflow-y-auto border border-gray-200 rounded-md p-2 space-y-2 bg-gray-50/50">
            {valueList.map((val) => (
              <div key={val} className="flex items-center gap-2 min-w-0">
                <Checkbox
                  className="shrink-0"
                  checked={selectedVals.includes(val)}
                  onCheckedChange={(checked) => {
                    const set = new Set(selectedVals);
                    if (checked) set.add(val);
                    else set.delete(val);
                    onPatch({ selectedOptionValues: Array.from(set) });
                  }}
                />
                <span className="text-xs truncate" title={val}>
                  {val}
                </span>
              </div>
            ))}
          </div>
        </div>
      ) : selectedId ? (
        <p className="text-[10px] text-amber-600">No values in this dictionary or still loading.</p>
      ) : null}
    </>
  );
}

function TextStaticStyleFields({
  cfg,
  update,
  textAlignDefault,
}: {
  cfg: Record<string, unknown>;
  update: (key: string, value: unknown) => void;
  textAlignDefault: string;
}) {
  return (
    <>
      <div>
        <Label className="text-xs">Text</Label>
        <Input
          value={(cfg.text as string) ?? '0.00'}
          onChange={(e) => update('text', e.target.value)}
          className="h-8 text-sm mt-1"
        />
      </div>
      <div>
        <Label className="text-xs">Font Size</Label>
        <Input
          type="number"
          value={(cfg.fontSize as number) ?? 14}
          onChange={(e) => update('fontSize', Number(e.target.value) || 14)}
          className="h-8 text-sm mt-1"
        />
      </div>
      <div>
        <Label className="text-xs">Text Align</Label>
        <Select
          value={(cfg.textAlign as string) ?? textAlignDefault}
          onValueChange={(v) => update('textAlign', v)}
        >
          <SelectTrigger className="h-8 text-sm mt-1">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="left">Left</SelectItem>
            <SelectItem value="center">Center</SelectItem>
            <SelectItem value="right">Right</SelectItem>
          </SelectContent>
        </Select>
      </div>
    </>
  );
}

/** 读 config（兼容后端 PascalCase、数字以字符串下发） */
function cfgPickStr(cfg: Record<string, unknown>, keys: string[], fallback: string): string {
  for (const k of keys) {
    const v = cfg[k];
    if (v != null && String(v).trim() !== '') return String(v).trim();
  }
  return fallback;
}

function cfgPickNum(cfg: Record<string, unknown>, keys: string[], fallback: number): number {
  for (const k of keys) {
    const v = cfg[k];
    if (v == null || v === '') continue;
    const n = typeof v === 'number' ? v : Number(v);
    if (Number.isFinite(n)) return n;
  }
  return fallback;
}

const WEIGHT_UNIT_OPTIONS: Array<{ value: string; label: string }> = [
  { value: 'lb', label: 'Lb' },
  { value: 'kg', label: 'Kg' },
  { value: 'mg', label: 'Milligrams' },
  { value: 'g', label: 'Grams' },
  { value: 'oz', label: 'Ounces' },
];

function normalizeWeightUnit(raw: unknown): string {
  const unit = String(raw ?? '').trim().toLowerCase();
  if (unit === 'milligrams') return 'mg';
  if (unit === 'grams') return 'g';
  if (unit === 'ounces') return 'oz';
  if (unit === 'pounds') return 'lb';
  if (unit === 'kilograms') return 'kg';
  if (WEIGHT_UNIT_OPTIONS.some((item) => item.value === unit)) return unit;
  return 'g';
}

function nutritionExtraRows(cfg: Record<string, unknown>): NutritionExtraItem[] {
  const raw = cfg.extraNutrients;
  if (!Array.isArray(raw)) return [];
  return raw.map((item, idx) => {
    const row = item as Record<string, unknown>;
    return {
      id: String(row.id ?? `extra-${idx}`),
      name: String(row.name ?? ''),
      value: String(row.value ?? ''),
      unit: String(row.unit ?? ''),
    };
  });
}

function nutritionFixedField(
  cfg: Record<string, unknown>,
  key: string,
  field: 'value' | 'unit',
): string {
  const directKey = field === 'value' ? key : `${key}Unit`;
  const direct = cfg[directKey];
  if (direct != null && String(direct).trim() !== '') return String(direct).trim();
  const fixedRows = Array.isArray(cfg.fixedNutrients)
    ? (cfg.fixedNutrients as Record<string, unknown>[])
    : [];
  const row = fixedRows.find((item) => String(item.key ?? '').trim() === key);
  return String(row?.[field] ?? '').trim();
}

function ElementConfigFields({
  element,
  onChange,
}: {
  element: LabelElement;
  onChange: (config: Record<string, unknown>) => void;
}) {
  const cfg = element.config as Record<string, unknown>;
  const elementType = canonicalElementType(element.type);
  const update = (key: string, value: unknown) =>
    onChange({ [key]: value });

  switch (elementType) {
    case 'TEXT_STATIC':
      if (cfg.inputType === 'options') {
        return (
          <>
            <MultipleOptionsDictionaryFields cfg={cfg} onPatch={onChange} />
            <TextStaticStyleFields cfg={cfg} update={update} textAlignDefault="left" />
          </>
        );
      }
      return <TextStaticStyleFields cfg={cfg} update={update} textAlignDefault="right" />;
    case 'TEXT_PRODUCT':
    case 'TEXT_PRICE':
      return <TextStaticStyleFields cfg={cfg} update={update} textAlignDefault="right" />;
    case 'BARCODE':
      return (
        <>
          <div>
            <Label className="text-xs">Data</Label>
            <Input
              value={(cfg.data as string) ?? '123456789'}
              onChange={(e) => update('data', e.target.value)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Orientation</Label>
            <Select
              value={(cfg.orientation as string) ?? 'horizontal'}
              onValueChange={(v) => update('orientation', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="horizontal">Horizontal</SelectItem>
                <SelectItem value="vertical">Vertical</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div className="flex items-center gap-2">
            <Switch
              checked={(cfg.showText as boolean) !== false}
              onCheckedChange={(v) => update('showText', v)}
            />
            <Label className="text-xs">Show Text</Label>
          </div>
        </>
      );
    case 'QRCODE':
      return (
        <div>
          <Label className="text-xs">Data (URL)</Label>
          <Input
            value={(cfg.data as string) ?? 'https://example.com'}
            onChange={(e) => update('data', e.target.value)}
            className="h-8 text-sm mt-1"
          />
        </div>
      );
    case 'IMAGE':
      return (
        <>
          <div>
            <Label className="text-xs">Image URL / path</Label>
            <Input
              value={(cfg.src as string) ?? ''}
              onChange={(e) => update('src', e.target.value)}
              className="h-8 text-sm mt-1"
              placeholder="https://... or /picture/..."
            />
          </div>
          <div>
            <Label className="text-xs">Scale Mode</Label>
            <Select
              value={(cfg.scaleMode as string) ?? 'contain'}
              onValueChange={(v) => update('scaleMode', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="contain">Contain</SelectItem>
                <SelectItem value="cover">Cover</SelectItem>
                <SelectItem value="fill">Fill</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </>
      );
    case 'DATE': {
      const inputTypeNorm = String(cfg.inputType ?? cfg.InputType ?? '').toLowerCase();
      const isPrintDate = inputTypeNorm === 'datetime' || inputTypeNorm === 'date';
      const dateFormat = cfgPickStr(
        cfg,
        ['format', 'Format'],
        inputTypeNorm === 'datetime' ? DATETIME_DEFAULT_FORMAT : 'DD/MM/YYYY',
      );
      const formatOptions =
        inputTypeNorm === 'datetime'
          ? [DATETIME_DEFAULT_FORMAT, ...DATE_FORMAT_OPTIONS]
          : [...DATE_FORMAT_OPTIONS];
      return (
        <>
          <div>
            <Label className="text-xs">Format</Label>
            <Select value={dateFormat} onValueChange={(v) => update('format', v)}>
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {formatOptions.map((fmt) => (
                  <SelectItem key={fmt} value={fmt}>
                    {fmt}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            {isPrintDate ? (
              <p className="text-[10px] text-gray-400 mt-1">
                Shown as placeholder on the label until the app fills the date at print time.
              </p>
            ) : null}
          </div>
          <div>
            <Label className="text-xs">Font Size</Label>
            <Input
              type="number"
              value={cfgPickNum(cfg, ['fontSize', 'FontSize'], 14)}
              onChange={(e) => update('fontSize', Number(e.target.value) || 14)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Text Align</Label>
            <Select
              value={cfgPickStr(cfg, ['textAlign', 'TextAlign'], 'left')}
              onValueChange={(v) => update('textAlign', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="left">Left</SelectItem>
                <SelectItem value="center">Center</SelectItem>
                <SelectItem value="right">Right</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </>
      );
    }
    case 'TIME':
      return (
        <>
          <div>
            <Label className="text-xs">Format</Label>
            <Input value="HH:mm" className="h-8 text-sm mt-1" readOnly />
          </div>
          <div>
            <Label className="text-xs">Font Size</Label>
            <Input
              type="number"
              value={cfgPickNum(cfg, ['fontSize', 'FontSize'], 14)}
              onChange={(e) => update('fontSize', Number(e.target.value) || 14)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Text Align</Label>
            <Select
              value={cfgPickStr(cfg, ['textAlign', 'TextAlign'], 'left')}
              onValueChange={(v) => update('textAlign', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="left">Left</SelectItem>
                <SelectItem value="center">Center</SelectItem>
                <SelectItem value="right">Right</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </>
      );
    case 'DURATION':
      return (
        <>
          <div>
            <Label className="text-xs">Format</Label>
            <Select
              value={cfgPickStr(cfg, ['format', 'Format'], 'Days')}
              onValueChange={(v) => update('format', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {DURATION_FORMAT_OPTIONS.map((fmt) => (
                  <SelectItem key={fmt} value={fmt}>
                    {fmt}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div>
            <Label className="text-xs">Font Size</Label>
            <Input
              type="number"
              value={cfgPickNum(cfg, ['fontSize', 'FontSize'], 14)}
              onChange={(e) => update('fontSize', Number(e.target.value) || 14)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Text Align</Label>
            <Select
              value={cfgPickStr(cfg, ['textAlign', 'TextAlign'], 'left')}
              onValueChange={(v) => update('textAlign', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="left">Left</SelectItem>
                <SelectItem value="center">Center</SelectItem>
                <SelectItem value="right">Right</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </>
      );
    case 'WEIGHT':
      {
        const weightUnit = normalizeWeightUnit(cfgPickStr(cfg, ['unit', 'Unit'], 'g'));
        const textAlign = cfgPickStr(cfg, ['textAlign', 'TextAlign'], 'left');
        const fontSize = cfgPickNum(cfg, ['fontSize', 'FontSize'], 14);
        return (
          <>
            <div>
              <Label className="text-xs">Value</Label>
              <Input
                type="number"
                value={cfgPickNum(cfg, ['value', 'Value'], 500)}
                onChange={(e) => update('value', Number(e.target.value) || 0)}
                className="h-8 text-sm mt-1"
              />
            </div>
            <div>
              <Label className="text-xs">Unit</Label>
              <Select
                value={weightUnit}
                onValueChange={(v) => update('unit', v)}
              >
                <SelectTrigger className="h-8 text-sm mt-1">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {WEIGHT_UNIT_OPTIONS.map((item) => (
                    <SelectItem key={item.value} value={item.value}>
                      {item.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div>
              <Label className="text-xs">Font Size</Label>
              <Input
                type="number"
                value={fontSize}
                onChange={(e) => update('fontSize', Math.max(1, Number(e.target.value) || 14))}
                className="h-8 text-sm mt-1"
              />
            </div>
            <div>
              <Label className="text-xs">Text Align</Label>
              <Select
                value={textAlign}
                onValueChange={(v) => update('textAlign', v)}
              >
                <SelectTrigger className="h-8 text-sm mt-1">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="left">Left</SelectItem>
                  <SelectItem value="center">Center</SelectItem>
                  <SelectItem value="right">Right</SelectItem>
                </SelectContent>
              </Select>
            </div>
          </>
        );
      }
    case 'WEIGHT_PRICE':
      return (
        <>
          <div>
            <Label className="text-xs">Unit Price</Label>
            <Input
              type="number"
              value={(cfg.unitPrice as number) ?? 10}
              onChange={(e) => update('unitPrice', Number(e.target.value) || 0)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Weight</Label>
            <Input
              type="number"
              step="0.1"
              value={(cfg.weight as number) ?? 0.5}
              onChange={(e) => update('weight', Number(e.target.value) || 0)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Currency</Label>
            <Input
              value={(cfg.currency as string) ?? '$'}
              onChange={(e) => update('currency', e.target.value)}
              className="h-8 text-sm mt-1"
            />
          </div>
        </>
      );
    case 'NUTRITION':
      {
        const extraRows = nutritionExtraRows(cfg);
        const applyFixedNutrients = (
          key: string,
          field: 'value' | 'unit',
          nextValue: string,
        ) => {
          const fixedRows = NUTRITION_FIXED_ITEMS.map((item) => {
            const current = {
              key: item.key,
              label: item.label,
              value: nutritionFixedField(cfg, item.key, 'value'),
              unit: nutritionFixedField(cfg, item.key, 'unit'),
            };
            if (item.key !== key) return current;
            return { ...current, [field]: nextValue };
          });
          const keyPatch: Record<string, unknown> = { fixedNutrients: fixedRows };
          const target = fixedRows.find((item) => item.key === key);
          if (target) {
            keyPatch[key] = target.value;
            keyPatch[`${key}Unit`] = target.unit;
          }
          onChange(keyPatch);
        };

        const addExtraNutrient = () => {
          const next: NutritionExtraItem[] = [
            ...extraRows,
            {
              id: `extra-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
              name: '',
              value: '',
              unit: '',
            },
          ];
          update('extraNutrients', next);
        };

        const updateExtraNutrient = (
          id: string,
          field: keyof NutritionExtraItem,
          nextValue: string,
        ) => {
          const next = extraRows.map((item) =>
            item.id === id ? { ...item, [field]: nextValue } : item,
          );
          update('extraNutrients', next);
        };

        const removeExtraNutrient = (id: string) => {
          update(
            'extraNutrients',
            extraRows.filter((item) => item.id !== id),
          );
        };

        return (
          <>
            <div>
              <Label className="text-xs">Nutrition summary</Label>
              <div className="space-y-2 mt-1">
                <div className="grid grid-cols-[1fr_90px] gap-2 items-center">
                  <span className="text-xs text-gray-600">Nutrition Facts title (px)</span>
                  <Input
                    type="number"
                    value={cfgPickNum(cfg, ['nutritionTitleFontSize', 'NutritionTitleFontSize'], 16)}
                    onChange={(e) =>
                      update('nutritionTitleFontSize', Math.max(10, Number(e.target.value) || 16))
                    }
                    className="h-8 text-sm"
                  />
                </div>
                <div className="grid grid-cols-[1fr_90px] gap-2 items-center">
                  <span className="text-xs text-gray-600">Servings Per Container</span>
                  <Input
                    value={cfgPickStr(cfg, ['servingsPerContainer', 'ServingsPerContainer'], '')}
                    onChange={(e) => update('servingsPerContainer', e.target.value)}
                    className="h-8 text-sm"
                    placeholder="e.g. 8"
                  />
                </div>
                <div className="grid grid-cols-[1fr_90px] gap-2 items-center">
                  <span className="text-xs text-gray-600">Serving Size</span>
                  <Input
                    value={cfgPickStr(cfg, ['servingSize', 'ServingSize'], '')}
                    onChange={(e) => update('servingSize', e.target.value)}
                    className="h-8 text-sm"
                    placeholder="e.g. 1 cup"
                  />
                </div>
                <div className="grid grid-cols-[1fr_90px] gap-2 items-center">
                  <span className="text-xs text-gray-600">Calories</span>
                  <Input
                    value={cfgPickStr(cfg, ['calories', 'Calories'], '')}
                    onChange={(e) => update('calories', e.target.value)}
                    className="h-8 text-sm"
                    placeholder="e.g. 120"
                  />
                </div>
              </div>
            </div>
            <div>
              <div className="flex items-center justify-between mb-1">
                <Label className="text-xs">Nutrition table</Label>
                <Button type="button" variant="outline" className="h-7 px-2 text-xs" onClick={addExtraNutrient}>
                  Add nutrient
                </Button>
              </div>
              <div className="space-y-1.5 mt-1">
                <div className="grid grid-cols-[1fr_78px_58px_26px] gap-1.5 items-center text-[10px] text-gray-500 px-0.5">
                  <span>Name</span>
                  <span>Value</span>
                  <span>Unit</span>
                  <span />
                </div>
                {NUTRITION_FIXED_ITEMS.map((item) => (
                  <div key={item.key} className="grid grid-cols-[1fr_78px_58px_26px] gap-1.5 items-center">
                    <span className="text-xs text-gray-600">{item.label}</span>
                    <Input
                      value={nutritionFixedField(cfg, item.key, 'value')}
                      onChange={(e) =>
                        applyFixedNutrients(item.key, 'value', e.target.value)
                      }
                      className="h-8 text-sm"
                      placeholder="Value"
                    />
                    <Input
                      value={nutritionFixedField(cfg, item.key, 'unit') || (item.defaultUnit ?? '')}
                      onChange={(e) =>
                        applyFixedNutrients(item.key, 'unit', e.target.value)
                      }
                      className="h-8 text-sm"
                      placeholder="Unit"
                    />
                    <span />
                  </div>
                ))}
              </div>
            </div>
            <div className="space-y-2">
              {extraRows.length === 0 ? (
                <p className="text-[10px] text-gray-400">No custom nutrients yet.</p>
              ) : (
                extraRows.map((row) => (
                  <div key={row.id} className="grid grid-cols-[1fr_78px_58px_26px] gap-1.5 items-center">
                    <Input
                      value={row.name}
                      onChange={(e) => updateExtraNutrient(row.id, 'name', e.target.value)}
                      className="h-8 text-sm"
                      placeholder="Name"
                    />
                    <Input
                      value={row.value}
                      onChange={(e) => updateExtraNutrient(row.id, 'value', e.target.value)}
                      className="h-8 text-sm"
                      placeholder="Value"
                    />
                    <Input
                      value={row.unit}
                      onChange={(e) => updateExtraNutrient(row.id, 'unit', e.target.value)}
                      className="h-8 text-sm"
                      placeholder="Unit"
                    />
                    <Button
                      type="button"
                      variant="ghost"
                      className="h-8 w-8 p-0 text-gray-500 hover:text-red-600"
                      onClick={() => removeExtraNutrient(row.id)}
                      aria-label="Delete nutrient"
                    >
                      <Trash2 className="h-3.5 w-3.5" />
                    </Button>
                  </div>
                ))
              )}
              <div className="text-[10px] text-gray-400">
                Unit is appended after value in template preview.
              </div>
            </div>
          </>
        );
      }
    case 'BLANK':
      return (
        <div className="text-xs text-gray-500">
          Blank spacer; no configuration needed.
        </div>
      );
    default:
      return (
        <div className="text-xs text-gray-500">
          Config for {elementType} (edit in code if needed)
        </div>
      );
  }
}
