import React, { useMemo, useState } from "react";
import {
  Paper,
  Stack,
  Group,
  Button,
  Text,
  ActionIcon,
  NumberInput,
  ScrollArea,
  Table,
  Badge,
  Select,
  Switch,
  TextInput,
  Textarea,
  Divider,
  Collapse,
  Alert,
  Tooltip,
} from "@mantine/core";
import { DateInput } from "@mantine/dates";
import {
  IconCalendar,
  IconPlus,
  IconTrash,
  IconChevronDown,
  IconChevronRight,
  IconAlertTriangle,
  IconRoute,
  IconCoin,
} from "@tabler/icons-react";

/**
 * Travel Rules editor.
 *
 * Mirrors the legacy `internal_exchange_travel_rules` JSON, whose shape is
 *   { [resortName]: { [unitCode]: Rule[] } }
 * The resort is the offer's target resort, so here we persist only the
 * `{ [unitCode]: Rule[] }` slice into `raw_config.travel_rules`. The public
 * travel-rules endpoint re-nests it under the resort name on read.
 *
 * A Rule carries role/date scoping plus a `unit_points` block holding the
 * season point-tiers (white / blue / red) per stay-length, the early-bird /
 * peak acceptance flags, and plus_pay. Anything not covered by a structured
 * field survives via the per-rule "Advanced (raw JSON)" editor, so a rule
 * always round-trips losslessly.
 */

type SeasonColor = "white" | "blue" | "red";
const SEASON_COLORS: SeasonColor[] = ["white", "blue", "red"];
const SEASON_LABEL: Record<SeasonColor, string> = {
  white: "White (low)",
  blue: "Blue (mid)",
  red: "Red (peak)",
};
const SEASON_BADGE: Record<SeasonColor, string> = {
  white: "gray",
  blue: "blue",
  red: "red",
};

// Stay-length buckets that can hold a season-tier price row.
const PERIOD_TYPES = [
  "daily",
  "weekly",
  "short_break_3",
  "short_break_4",
  "nights_1",
  "nights_2",
  "nights_3",
  "nights_4",
  "nights_5",
  "nights_6",
  "nights_7",
];

const PERIOD_LABEL: Record<string, string> = {
  daily: "Daily",
  weekly: "Weekly",
  short_break_3: "Short Break 3",
  short_break_4: "Short Break 4",
  nights_1: "1 Night",
  nights_2: "2 Nights",
  nights_3: "3 Nights",
  nights_4: "4 Nights",
  nights_5: "5 Nights",
  nights_6: "6 Nights",
  nights_7: "7 Nights",
};

// Non-tier keys that live inside unit_points so we can list only real period rows.
const UNIT_POINTS_RESERVED = new Set([
  "accept_peaks",
  "accept_early_bird",
  "accept_late_break",
  "plus_pay",
  "use_calculation_offer_202405",
  "weekly_use_daily",
]);

export interface TravelRuleUnitOption {
  code: string;
  label: string;
}

interface OfferTravelRulesTabProps {
  rawConfig: Record<string, any>;
  setRawConfig: React.Dispatch<React.SetStateAction<Record<string, any>>>;
  canEdit: boolean;
  sectionTitle: (title: string, icon?: React.ReactNode) => React.ReactNode;
  /** The offer's selected units (unit_vp_code + name), used as travel-rule keys. */
  units?: TravelRuleUnitOption[];
}

type Rule = Record<string, any>;

const emptyRule = (): Rule => ({
  travel_between: [["", ""]],
  unit_points: {
    accept_early_bird: false,
    accept_late_break: false,
    accept_peaks: false,
  },
});

function toISODate(d: Date | null): string {
  return d ? d.toISOString().split("T")[0] : "";
}

export const OfferTravelRulesTab: React.FC<OfferTravelRulesTabProps> = ({
  rawConfig,
  setRawConfig,
  canEdit,
  sectionTitle,
  units = [],
}) => {
  const travelRules: Record<string, Rule[]> = rawConfig.travel_rules ?? {};

  // Unit keys come from the offer's units, unioned with any keys already stored
  // (so rules for a unit later removed from the offer are still reachable).
  const unitKeys = useMemo(() => {
    const fromUnits = units.map((u) => u.code).filter(Boolean);
    const fromStored = Object.keys(travelRules);
    return Array.from(new Set([...fromUnits, ...fromStored]));
  }, [units, travelRules]);

  const [selectedUnit, setSelectedUnit] = useState<string | null>(
    unitKeys[0] ?? null,
  );

  const activeUnit = selectedUnit && unitKeys.includes(selectedUnit)
    ? selectedUnit
    : unitKeys[0] ?? null;

  const labelFor = (code: string) =>
    units.find((u) => u.code === code)?.label ?? code;

  // ---- mutation helpers (immutable) --------------------------------------
  const commit = (nextForUnit: Rule[], unit: string) => {
    setRawConfig((prev) => ({
      ...prev,
      travel_rules: { ...(prev.travel_rules ?? {}), [unit]: nextForUnit },
    }));
  };

  const rulesForActive: Rule[] = (activeUnit && travelRules[activeUnit]) || [];

  const addRule = () => {
    if (!activeUnit) return;
    commit([...rulesForActive, emptyRule()], activeUnit);
  };

  const removeRule = (idx: number) => {
    if (!activeUnit) return;
    const next = [...rulesForActive];
    next.splice(idx, 1);
    commit(next, activeUnit);
  };

  const patchRule = (idx: number, patch: Rule) => {
    if (!activeUnit) return;
    const next = rulesForActive.map((r, i) => (i === idx ? { ...r, ...patch } : r));
    commit(next, activeUnit);
  };

  const replaceRule = (idx: number, rule: Rule) => {
    if (!activeUnit) return;
    const next = rulesForActive.map((r, i) => (i === idx ? rule : r));
    commit(next, activeUnit);
  };

  return (
    <Stack gap="xl">
      {units.length === 0 && unitKeys.length === 0 && (
        <Alert
          color="yellow"
          icon={<IconAlertTriangle size={18} />}
          title="Add eligible units first"
        >
          Travel rules are defined per unit code. Select the eligible units on the
          Configuration tab, then return here to add their season point-tiers,
          early-bird and peak rules.
        </Alert>
      )}

      {/* Unit selector */}
      <Paper
        withBorder
        radius="lg"
        p="lg"
        style={{ boxShadow: "0 4px 16px rgba(0,0,0,0.01)", background: "#ffffff" }}
      >
        {sectionTitle("Travel Rules by Unit", <IconRoute size={20} style={{ color: "#868e96" }} />)}
        <Group align="flex-end" justify="space-between">
          <Select
            label="Unit code"
            description="Rules apply to this unit; the resort is the offer's target resort."
            data={unitKeys.map((c) => ({
              value: c,
              label: labelFor(c) === c ? c : `${c} — ${labelFor(c)}`,
            }))}
            value={activeUnit}
            onChange={setSelectedUnit}
            placeholder="Select unit"
            searchable
            w={360}
            nothingFoundMessage="No units on this offer"
          />
          <Badge size="lg" variant="light" color="grape">
            {rulesForActive.length} rule{rulesForActive.length === 1 ? "" : "s"}
          </Badge>
        </Group>
      </Paper>

      {activeUnit && (
        <Stack gap="lg">
          {rulesForActive.length === 0 && (
            <Text c="dimmed" ta="center">
              No travel rules for <b>{labelFor(activeUnit)}</b> yet.
            </Text>
          )}
          {rulesForActive.map((rule, idx) => (
            <RuleCard
              key={idx}
              index={idx}
              rule={rule}
              canEdit={canEdit}
              onPatch={(patch) => patchRule(idx, patch)}
              onReplace={(r) => replaceRule(idx, r)}
              onRemove={() => removeRule(idx)}
            />
          ))}
          {canEdit && (
            <Group>
              <Button
                variant="light"
                color="grape"
                leftSection={<IconPlus size={16} />}
                onClick={addRule}
              >
                Add Rule for {labelFor(activeUnit)}
              </Button>
            </Group>
          )}
        </Stack>
      )}
    </Stack>
  );
};

// ===========================================================================
// Rule card
// ===========================================================================

interface RuleCardProps {
  index: number;
  rule: Rule;
  canEdit: boolean;
  onPatch: (patch: Rule) => void;
  onReplace: (rule: Rule) => void;
  onRemove: () => void;
}

const RuleCard: React.FC<RuleCardProps> = ({
  index,
  rule,
  canEdit,
  onPatch,
  onReplace,
  onRemove,
}) => {
  const [advancedOpen, setAdvancedOpen] = useState(false);
  const [plusPayOpen, setPlusPayOpen] = useState(false);

  const unitPoints: Record<string, any> = rule.unit_points ?? {};

  const patchUnitPoints = (patch: Record<string, any>) => {
    onPatch({ unit_points: { ...unitPoints, ...patch } });
  };

  // ---- travel_between ----
  const travelBetween: [string, string][] = rule.travel_between ?? [["", ""]];
  const setTravelDate = (i: number, se: 0 | 1, val: Date | null) => {
    const next = travelBetween.map((r) => [...r]) as [string, string][];
    if (!next[i]) next[i] = ["", ""];
    next[i][se] = toISODate(val);
    onPatch({ travel_between: next });
  };
  const addTravelDate = () => onPatch({ travel_between: [...travelBetween, ["", ""]] });
  const removeTravelDate = (i: number) => {
    const next = travelBetween.filter((_, x) => x !== i);
    onPatch({ travel_between: next.length ? next : [["", ""]] });
  };

  // ---- season tier rows ----
  const periodKeys = Object.keys(unitPoints).filter(
    (k) => !UNIT_POINTS_RESERVED.has(k) && !k.endsWith("XXX") && !k.startsWith("__"),
  );
  const availablePeriods = PERIOD_TYPES.filter((p) => !periodKeys.includes(p));

  const setTierValue = (period: string, color: SeasonColor, val: number | string) => {
    const tier = { ...(unitPoints[period] ?? {}) };
    if (val === "" || val === null || val === undefined) {
      delete tier[color];
    } else {
      tier[color] = Number(val);
    }
    patchUnitPoints({ [period]: tier });
  };
  const addPeriod = (period: string | null) => {
    if (!period) return;
    patchUnitPoints({ [period]: {} });
  };
  const removePeriod = (period: string) => {
    const next = { ...unitPoints };
    delete next[period];
    onPatch({ unit_points: next });
  };

  // ---- advanced raw JSON ----
  const [jsonDraft, setJsonDraft] = useState<string>(() =>
    JSON.stringify(rule, null, 2),
  );
  const [jsonError, setJsonError] = useState<string | null>(null);
  const applyJson = () => {
    try {
      const parsed = JSON.parse(jsonDraft);
      setJsonError(null);
      onReplace(parsed);
    } catch (e: any) {
      setJsonError(e.message ?? "Invalid JSON");
    }
  };

  const rolesText = Array.isArray(rule.roles)
    ? rule.roles.filter((r: any) => typeof r === "string").join(", ")
    : "";
  const hasComplexRoles =
    Array.isArray(rule.roles) && rule.roles.some((r: any) => typeof r !== "string");

  return (
    <Paper
      withBorder
      radius="lg"
      p="lg"
      style={{ boxShadow: "0 4px 16px rgba(0,0,0,0.01)", background: "#ffffff" }}
    >
      <Group justify="space-between" mb="md">
        <Group gap="xs">
          <Badge size="lg" variant="filled" color="grape">
            Rule {index + 1}
          </Badge>
          {rule.rule_id && (
            <Badge size="lg" variant="light" color="gray">
              id: {rule.rule_id}
            </Badge>
          )}
        </Group>
        {canEdit && (
          <ActionIcon color="red" variant="subtle" onClick={onRemove}>
            <IconTrash size={18} />
          </ActionIcon>
        )}
      </Group>

      <Stack gap="lg">
        {/* Behaviour flags */}
        <div>
          <Text fw={600} size="sm" mb="xs">
            Acceptance flags
          </Text>
          <Group gap="xl">
            <Switch
              label="Accept early bird"
              checked={!!unitPoints.accept_early_bird}
              onChange={(e) => patchUnitPoints({ accept_early_bird: e.currentTarget.checked })}
              disabled={!canEdit}
            />
            <Switch
              label="Accept late break"
              checked={!!unitPoints.accept_late_break}
              onChange={(e) => patchUnitPoints({ accept_late_break: e.currentTarget.checked })}
              disabled={!canEdit}
            />
            <Switch
              label="Accept peaks"
              checked={!!unitPoints.accept_peaks}
              onChange={(e) => patchUnitPoints({ accept_peaks: e.currentTarget.checked })}
              disabled={!canEdit}
            />
          </Group>
        </div>

        <Divider />

        {/* Constraints */}
        <div>
          <Text fw={600} size="sm" mb="xs">
            Constraints
          </Text>
          <Group grow align="flex-start">
            <NumberInput
              label="Min nights"
              value={rule.min_nights ?? ""}
              onChange={(v) => onPatch({ min_nights: v === "" ? undefined : Number(v) })}
              disabled={!canEdit}
              hideControls
            />
            <NumberInput
              label="Max nights"
              value={rule.max_nights ?? ""}
              onChange={(v) => onPatch({ max_nights: v === "" ? undefined : Number(v) })}
              disabled={!canEdit}
              hideControls
            />
            <NumberInput
              label="Max occupancy"
              value={rule.max_occ ?? ""}
              onChange={(v) => onPatch({ max_occ: v === "" ? undefined : Number(v) })}
              disabled={!canEdit}
              hideControls
            />
          </Group>
          <Group grow align="flex-start" mt="sm">
            <DateInput
              label="Confirm from"
              value={rule.confirm_from ? new Date(rule.confirm_from) : null}
              onChange={(v: any) => onPatch({ confirm_from: v ? new Date(v).toISOString() : undefined })}
              disabled={!canEdit}
              valueFormat="DD MMM YYYY"
              clearable
            />
            <DateInput
              label="Confirm to"
              value={rule.confirm_to ? new Date(rule.confirm_to) : null}
              onChange={(v: any) => onPatch({ confirm_to: v ? new Date(v).toISOString() : undefined })}
              disabled={!canEdit}
              valueFormat="DD MMM YYYY"
              clearable
            />
            <NumberInput
              label="Hot deal type"
              value={rule.hot_deal_type ?? ""}
              onChange={(v) => onPatch({ hot_deal_type: v === "" ? undefined : Number(v) })}
              disabled={!canEdit}
              hideControls
            />
          </Group>
          <Group grow align="flex-start" mt="sm">
            <TextInput
              label="Rule ID"
              value={rule.rule_id ?? ""}
              onChange={(e) => onPatch({ rule_id: e.currentTarget.value || undefined })}
              disabled={!canEdit}
            />
            <TextInput
              label="Booking caption"
              value={rule.booking_caption ?? ""}
              onChange={(e) => onPatch({ booking_caption: e.currentTarget.value || undefined })}
              disabled={!canEdit}
            />
          </Group>
          <Group gap="xl" mt="md">
            <Switch
              label="With check-in day"
              checked={!!rule.with_checkin_day}
              onChange={(e) => onPatch({ with_checkin_day: e.currentTarget.checked })}
              disabled={!canEdit}
            />
            <Switch
              label="Expose option"
              checked={!!rule.expose_option}
              onChange={(e) => onPatch({ expose_option: e.currentTarget.checked })}
              disabled={!canEdit}
            />
          </Group>
        </div>

        <Divider />

        {/* Roles */}
        <div>
          <TextInput
            label="Roles (comma separated)"
            description="Simple string roles. Complex {and:[…]} conditions are preserved via Advanced."
            value={rolesText}
            onChange={(e) => {
              const strings = e.currentTarget.value
                .split(",")
                .map((s) => s.trim())
                .filter(Boolean);
              const complex = Array.isArray(rule.roles)
                ? rule.roles.filter((r: any) => typeof r !== "string")
                : [];
              onPatch({ roles: [...strings, ...complex] });
            }}
            disabled={!canEdit}
          />
          {hasComplexRoles && (
            <Text size="xs" c="dimmed" mt={4}>
              This rule also has complex role conditions — edit them under Advanced.
            </Text>
          )}
        </div>

        <Divider />

        {/* Travel dates */}
        <div>
          <Text fw={600} size="sm" mb="xs">
            <Group gap={6} component="span">
              <IconCalendar size={16} style={{ color: "#868e96" }} /> Travel dates
            </Group>
          </Text>
          <Stack gap="sm">
            {travelBetween.map((range, i) => (
              <Group key={i} align="flex-end">
                <Badge size="md" variant="light">{i + 1}</Badge>
                <DateInput
                  label="Start"
                  value={range[0] ? new Date(range[0]) : null}
                  onChange={(v: any) => setTravelDate(i, 0, v)}
                  disabled={!canEdit}
                  valueFormat="DD MMM YYYY"
                  clearable
                />
                <DateInput
                  label="End"
                  value={range[1] ? new Date(range[1]) : null}
                  onChange={(v: any) => setTravelDate(i, 1, v)}
                  disabled={!canEdit}
                  valueFormat="DD MMM YYYY"
                  clearable
                />
                {canEdit && (
                  <ActionIcon color="red" variant="subtle" onClick={() => removeTravelDate(i)} mb={4}>
                    <IconTrash size={18} />
                  </ActionIcon>
                )}
              </Group>
            ))}
            {canEdit && (
              <Group>
                <Button variant="subtle" size="xs" leftSection={<IconPlus size={14} />} onClick={addTravelDate}>
                  Add date range
                </Button>
              </Group>
            )}
          </Stack>
        </div>

        <Divider />

        {/* Season point tiers */}
        <div>
          <Text fw={600} size="sm" mb="xs">
            Season point-tiers (unit_points)
          </Text>
          <Text size="xs" c="dimmed" mb="sm">
            Points charged per stay-length, by season colour.
          </Text>
          <ScrollArea>
            <Table withTableBorder withColumnBorders>
              <Table.Thead>
                <Table.Tr>
                  <Table.Th>Stay length</Table.Th>
                  {SEASON_COLORS.map((c) => (
                    <Table.Th key={c} ta="center">
                      <Badge color={SEASON_BADGE[c]} variant="light">{SEASON_LABEL[c]}</Badge>
                    </Table.Th>
                  ))}
                  {canEdit && <Table.Th w={50} />}
                </Table.Tr>
              </Table.Thead>
              <Table.Tbody>
                {periodKeys.length === 0 && (
                  <Table.Tr>
                    <Table.Td colSpan={SEASON_COLORS.length + 2} ta="center">
                      <Text c="dimmed" size="sm">No point-tiers defined.</Text>
                    </Table.Td>
                  </Table.Tr>
                )}
                {periodKeys.map((period) => {
                  const tier = unitPoints[period] ?? {};
                  const isFlatOrObj = typeof tier === "object" && tier !== null;
                  return (
                    <Table.Tr key={period}>
                      <Table.Td fw={600}>{PERIOD_LABEL[period] ?? period}</Table.Td>
                      {SEASON_COLORS.map((c) => {
                        const cell = isFlatOrObj ? tier[c] : undefined;
                        const editable = typeof cell === "number" || cell === undefined;
                        return (
                          <Table.Td key={c}>
                            {editable ? (
                              <NumberInput
                                value={typeof cell === "number" ? cell : ""}
                                onChange={(v) => setTierValue(period, c, v)}
                                disabled={!canEdit}
                                hideControls
                                decimalScale={2}
                                styles={{ input: { textAlign: "center" } }}
                              />
                            ) : (
                              <Tooltip label="Non-numeric value — edit via Advanced">
                                <Text size="xs" c="dimmed" ta="center">complex</Text>
                              </Tooltip>
                            )}
                          </Table.Td>
                        );
                      })}
                      {canEdit && (
                        <Table.Td>
                          <ActionIcon color="red" variant="subtle" onClick={() => removePeriod(period)}>
                            <IconTrash size={16} />
                          </ActionIcon>
                        </Table.Td>
                      )}
                    </Table.Tr>
                  );
                })}
              </Table.Tbody>
            </Table>
          </ScrollArea>
          {canEdit && availablePeriods.length > 0 && (
            <Group mt="sm">
              <Select
                placeholder="Add stay length…"
                data={availablePeriods.map((p) => ({ value: p, label: PERIOD_LABEL[p] ?? p }))}
                value={null}
                onChange={addPeriod}
                w={220}
                size="xs"
              />
            </Group>
          )}
        </div>

        <Divider />

        {/* plus_pay */}
        <div>
          <Button
            variant="subtle"
            size="xs"
            leftSection={plusPayOpen ? <IconChevronDown size={14} /> : <IconChevronRight size={14} />}
            onClick={() => setPlusPayOpen((o) => !o)}
            color="gray"
          >
            <Group gap={6} component="span">
              <IconCoin size={14} /> Plus pay (paid supplement)
            </Group>
          </Button>
          <Collapse in={plusPayOpen}>
            <PlusPayEditor
              value={rule.unit_points?.plus_pay}
              canEdit={canEdit}
              onChange={(pp) => patchUnitPoints({ plus_pay: pp })}
            />
          </Collapse>
        </div>

        <Divider />

        {/* terms */}
        <Textarea
          label="Terms & conditions"
          autosize
          minRows={2}
          maxRows={6}
          value={rule.terms_conditions ?? ""}
          onChange={(e) => onPatch({ terms_conditions: e.currentTarget.value || undefined })}
          disabled={!canEdit}
        />

        <Divider />

        {/* Advanced raw JSON */}
        <div>
          <Button
            variant="subtle"
            size="xs"
            color="gray"
            leftSection={advancedOpen ? <IconChevronDown size={14} /> : <IconChevronRight size={14} />}
            onClick={() => {
              if (!advancedOpen) setJsonDraft(JSON.stringify(rule, null, 2));
              setAdvancedOpen((o) => !o);
            }}
          >
            Advanced (raw JSON) — overrides, plus_pay peak dates, check-in days
          </Button>
          <Collapse in={advancedOpen}>
            <Stack gap="xs" mt="sm">
              <Textarea
                value={jsonDraft}
                onChange={(e) => setJsonDraft(e.currentTarget.value)}
                autosize
                minRows={8}
                maxRows={30}
                disabled={!canEdit}
                styles={{ input: { fontFamily: "monospace", fontSize: 12 } }}
                error={jsonError}
              />
              {canEdit && (
                <Group>
                  <Button size="xs" onClick={applyJson}>Apply JSON</Button>
                  <Button
                    size="xs"
                    variant="subtle"
                    color="gray"
                    onClick={() => {
                      setJsonDraft(JSON.stringify(rule, null, 2));
                      setJsonError(null);
                    }}
                  >
                    Reset
                  </Button>
                </Group>
              )}
            </Stack>
          </Collapse>
        </div>
      </Stack>
    </Paper>
  );
};

// ===========================================================================
// plus_pay editor
// ===========================================================================

interface PlusPayEditorProps {
  value: any;
  canEdit: boolean;
  onChange: (v: any) => void;
}

const PlusPayEditor: React.FC<PlusPayEditorProps> = ({ value, canEdit, onChange }) => {
  const pp = value ?? {};
  const priceIsObject = typeof pp.price === "object" && pp.price !== null;
  const underAges: Record<string, any> = priceIsObject ? pp.price.under_ages ?? {} : {};

  const patch = (p: Record<string, any>) => onChange({ ...pp, ...p });

  const setAdultPrice = (v: number | string) => {
    if (priceIsObject) {
      patch({ price: { ...pp.price, under_ages: { ...underAges, adult: Number(v) } } });
    } else {
      patch({ price: v === "" ? undefined : Number(v) });
    }
  };

  const setUnderAge = (age: string, v: number | string) => {
    const next = { ...underAges, [age]: Number(v) };
    patch({ price: { ...(priceIsObject ? pp.price : {}), under_ages: next } });
  };
  const removeUnderAge = (age: string) => {
    const next = { ...underAges };
    delete next[age];
    patch({ price: { ...(priceIsObject ? pp.price : {}), under_ages: next } });
  };
  const [newAge, setNewAge] = useState("");

  if (value === undefined && !canEdit) {
    return <Text size="xs" c="dimmed" mt="sm">No plus-pay configured.</Text>;
  }

  return (
    <Stack gap="sm" mt="sm" pl="md" style={{ borderLeft: "2px solid #f1f3f5" }}>
      <Group grow align="flex-start">
        <TextInput
          label="Currency"
          placeholder="USD / INR"
          value={pp.currency ?? ""}
          onChange={(e) => patch({ currency: e.currentTarget.value || undefined })}
          disabled={!canEdit}
        />
        <NumberInput
          label={priceIsObject ? "Adult price" : "Price"}
          value={priceIsObject ? (underAges.adult ?? "") : (typeof pp.price === "number" ? pp.price : "")}
          onChange={(v) => setAdultPrice(v)}
          disabled={!canEdit}
          hideControls
        />
      </Group>

      <div>
        <Text size="xs" fw={600} mb={4}>Under-age pricing</Text>
        <Stack gap={6}>
          {Object.keys(underAges)
            .filter((a) => a !== "adult")
            .map((age) => (
              <Group key={age} gap="xs" align="flex-end">
                <TextInput label="Under age" value={age} disabled w={110} size="xs" />
                <NumberInput
                  label="Price"
                  value={typeof underAges[age] === "number" ? underAges[age] : ""}
                  onChange={(v) => setUnderAge(age, v)}
                  disabled={!canEdit}
                  hideControls
                  size="xs"
                />
                {canEdit && (
                  <ActionIcon color="red" variant="subtle" onClick={() => removeUnderAge(age)} mb={4}>
                    <IconTrash size={16} />
                  </ActionIcon>
                )}
              </Group>
            ))}
          {canEdit && (
            <Group gap="xs" align="flex-end">
              <TextInput
                label="Add under-age"
                placeholder="e.g. 13"
                value={newAge}
                onChange={(e) => setNewAge(e.currentTarget.value)}
                w={130}
                size="xs"
              />
              <Button
                size="xs"
                variant="light"
                leftSection={<IconPlus size={14} />}
                onClick={() => {
                  if (newAge.trim()) {
                    setUnderAge(newAge.trim(), 0);
                    setNewAge("");
                  }
                }}
              >
                Add
              </Button>
            </Group>
          )}
        </Stack>
      </div>
      <Text size="xs" c="dimmed">
        Peak-date supplements are edited under the rule's Advanced (raw JSON) section.
      </Text>
    </Stack>
  );
};
