import type { SidebarItem } from "@/components/layout/types";
import { ruleEngineViewKey } from "@/lib/permissions";
import type { RuleEngineResourceSlug } from "@/types/rule-engine";

export type RuleEngineNavCategory = "configuration" | "rules";

export type ColumnFormat =
  | "text"
  | "code"
  | "boolean"
  | "activeBadge"
  | "rateStatus"
  | "date"
  | "number"
  | "currency"
  | "entityLabel"
  | "rateLabel";

export type FormFieldType = "text" | "number" | "boolean" | "date" | "email" | "select" | "multiselect" | "textarea" | "radio";

export interface ResourceColumn {
  id: string;
  header: string;
  accessorKey: string;
  format?: ColumnFormat;
}

/** Radix Select cannot use empty string as an item value; use this for optional "none" choices. */
export const RULE_ENGINE_SELECT_NONE = "__none__";

export interface FormFieldDef {
  name: string;
  label: string;
  type: FormFieldType;
  required?: boolean;
  optional?: boolean;
  options?: { label: string; value: string }[];
  placeholder?: string;
  description?: string;
  disabled?: boolean;
  /** Trailing unit label shown inside the input (e.g. "USD" on a rate value). */
  suffix?: string;
  /** Hide this field when another field currently equals one of these values. */
  hideWhen?: { field: string; equals: string[] };
  /**
   * Show this field ONLY when another field currently equals one of these
   * values (inverse of hideWhen). When both are set, the field must satisfy
   * showWhen and not match hideWhen.
   */
  showWhen?: { field: string; equals: string[] };
  /**
   * Show this field only when the predicate accepts the live form values — for
   * visibility that depends on more than one field, which `showWhen` cannot
   * express (the intercity container/bulk pickers hang off both `appliesTo`
   * and `intercityKind`). Combines with showWhen/hideWhen: all must pass.
   */
  showIf?: (values: Record<string, unknown>) => boolean;
  /**
   * Select options computed from other fields' current values. When set, the
   * form resolves the option list at render time from the live form state
   * instead of the static `options` list. Used for the rate unit selector,
   * whose valid choices depend on `appliesTo` + `trigger`. (Named distinctly
   * from the fleet config's string-based `dynamicOptions` to avoid a clash.)
   */
  optionsFromValues?: (values: Record<string, unknown>) => { label: string; value: string }[];
  /**
   * Derive the field's initial form value from the record being edited when it
   * doesn't live under `record[name]` — e.g. a multiselect of ids backed by a
   * relation list (`wagonTypeIds` read from `record.wagonTypes`).
   */
  getInitialValue?: (record: Record<string, unknown>) => unknown;
  /**
   * Fully derived field: its value is computed from the live form values on
   * every render and the input is locked. Used for the priority-rule min
   * wagon count, which always continues the previous range for the selected
   * type. Return null/undefined to leave the field empty (e.g. chain full).
   */
  computeValue?: (values: Record<string, unknown>) => number | string | null;
}

export interface RuleEngineOrderConfig {
  field: "displayOrder" | "stepOrder";
  scopeField?: "requiresDirectorApproval";
  label: string;
}

/**
 * A category tab above a resource list. The active tab's `filters` are sent to
 * the list endpoint verbatim, so filtering happens server-side (values may be
 * comma-separated lists, e.g. appliesTo: "FIRST_MILE,LAST_MILE").
 */
export interface RuleEngineListTab {
  key: string;
  label: string;
  filters: { appliesTo?: string; trigger?: string };
}

export interface RuleEngineResourceConfig {
  slug: RuleEngineResourceSlug;
  label: string;
  subtitle: string;
  category: RuleEngineNavCategory;
  searchPlaceholder: string;
  columns: ResourceColumn[];
  formFields: FormFieldDef[];
  supportsSearch?: boolean;
  orderConfig?: RuleEngineOrderConfig;
  /** Server-filtered category tabs rendered above the list (rates page). */
  listTabs?: RuleEngineListTab[];
  /** Primary line on card view (inferred from columns when omitted). */
  cardTitleKey?: string;
  /** Secondary line under title on card view (inferred when omitted). */
  cardSubtitleKey?: string;
  /** Code badge on card header (inferred from code column when omitted). */
  cardCodeKey?: string;
}

export const RULE_ENGINE_CATEGORY_BASE_PATH: Record<RuleEngineNavCategory, string> = {
  configuration: "/dashboard/configuration",
  rules: "/dashboard/rules",
};

const TRADE_DIRECTIONS = [
  { label: "Import", value: "IMPORT" },
  { label: "Export", value: "EXPORT" },
  { label: "Both", value: "BOTH" },
];

// Mirrors the YardCountry enum in @edr/types — the only two countries on the line.
const YARD_COUNTRIES = [
  { label: "Ethiopia", value: "Ethiopia" },
  { label: "Djibouti", value: "Djibouti" },
];

/**
 * The three role strings the approval chain was hardcoded to before it was
 * driven by IAM position types. Kept only so rows still stored against them
 * render a readable label instead of a blank select — the live options come
 * from GET /approval-rules/position-types (see `useApprovalRoleOptions`).
 */
export const LEGACY_APPROVAL_ROLES = [
  { label: "Line staff (legacy)", value: "LINE_STAFF" },
  { label: "Director (legacy)", value: "DIRECTOR" },
  { label: "CEO (legacy)", value: "CEO" },
];

/**
 * Friendly, admin-facing rate categories. Choosing one drives which fields the
 * Rate form shows (see the `rates` resource below). Base-freight categories
 * carry a trade direction + container/bulk scope; OTHER is for surcharges.
 */
const RATE_APPLIES_TO = [
  { label: "Bulk (base freight)", value: "BULK" },
  { label: "Container (base freight)", value: "CONTAINER" },
  { label: "Intercity (base freight)", value: "INTERCITY" },
  { label: "First mile", value: "FIRST_MILE" },
  { label: "Last mile", value: "LAST_MILE" },
  { label: "Other (surcharge)", value: "OTHER" },
];

/** Surcharge triggers — only relevant when Applies to = Other. */
const RATE_TRIGGERS = [
  { label: "Hazardous cargo", value: "HAZARDOUS" },
  {
    label: "Overweight (export only — import derives from container price)",
    value: "OVERWEIGHT",
  },
  { label: "Reefer cargo", value: "REEFER" },
  {
    label: "Empty container return (import, per route + container type)",
    value: "WITH_RETURN",
  },
  { label: "Shipping line mapped", value: "SHIPPING_LINE" },
  { label: "Penalty", value: "CONSOLIDATION" },
  { label: "Lashing (bulk, per cargo type)", value: "LASHING" },
  { label: "Cancellation", value: "CANCELLATION" },
  { label: "Shipping line extra fee (PIL)", value: "PIL_EXTRA_FEE" },
  { label: "Customs clearance service fee (billed with the booking)", value: "CUSTOMS_CLEARANCE" },
];

/**
 * Intercity runs inside Ethiopia and can carry either boxes or bulk, but the
 * two price differently. The admin says which up front and the form then asks
 * for the matching scope field — this choice is not stored on the rate itself;
 * the API reads container-vs-bulk back off whichever scope field was filled.
 */
const INTERCITY_KINDS = [
  { label: "Container", value: "CONTAINER" },
  { label: "Bulk", value: "BULK" },
];

/** True when the rate being edited is base rail freight, which is priced per leg. */
const isBaseFreightRate = (values: Record<string, unknown>) =>
  ["BULK", "CONTAINER", "INTERCITY"].includes(String(values.appliesTo ?? ""));

/**
 * Rates priced per leg: base rail freight, plus the customs clearance fee and
 * the empty-container return surcharge (sold per route + container type).
 */
const isRouteScopedRate = (values: Record<string, unknown>) =>
  isBaseFreightRate(values) ||
  (String(values.appliesTo ?? "") === "OTHER" &&
    ["CUSTOMS_CLEARANCE", "WITH_RETURN"].includes(String(values.trigger ?? "")));

const unitOption = (value: string) => ({ label: value.replace(/_/g, " "), value });

/**
 * Valid weighting units for a rate shape — mirrors the API's
 * `allowedRateUnits`. The unit is driven by the *type* being billed: containers
 * bill per container, bulk per ton, overweight always per excess ton, etc. A
 * rate scoped to a break-bulk commodity (unit of measure = PER_ITEM) offers
 * PER_ITEM wherever a weighed one offers PER_TON. Kept in sync with
 * apps/edr-freight-api/.../entities/rate-unit.util.ts.
 */
const allowedRateUnits = (
  appliesTo: string,
  trigger: string,
  cargoKind = "",
  cargoUnitOfMeasure = "",
): string[] => {
  const units = unitsForShape(appliesTo, trigger, cargoKind);
  return cargoUnitOfMeasure === "PER_ITEM"
    ? units.map((u) => (u === "PER_TON" ? "PER_ITEM" : u))
    : units;
};

const unitsForShape = (
  appliesTo: string,
  trigger: string,
  cargoKind = "",
): string[] => {
  if (appliesTo === "OTHER") {
    switch (trigger) {
      case "OVERWEIGHT":
        return ["PER_TON"];
      case "REEFER":
      case "HAZARDOUS":
      case "DEMURRAGE":
        return ["PER_CONTAINER", "PER_TON"];
      case "WITH_RETURN":
        // Container-only service — per returned container, per wagon, or flat.
        return ["PER_CONTAINER", "PER_WAGON", "FLAT"];
      case "CANCELLATION":
        return ["FLAT", "PER_INVOICE"];
      case "CUSTOMS_CLEARANCE":
        // Per cargo kind: container fees per box/wagon, bulk per ton/wagon.
        return cargoKind === "BULK"
          ? ["PER_TON", "PER_WAGON"]
          : ["PER_CONTAINER", "PER_WAGON"];
      case "LASHING":
        // Bulk-only cargo securing — per ton or per wagon.
        return ["PER_TON", "PER_WAGON"];
      case "CONSOLIDATION":
      case "SHIPPING_LINE":
      case "PIL_EXTRA_FEE":
        return ["PER_CONTAINER", "FLAT"];
      default:
        return ["FLAT", "PER_TON", "PER_CONTAINER"];
    }
  }
  switch (appliesTo) {
    case "CONTAINER":
      return ["PER_CONTAINER", "PER_WAGON"];
    case "BULK":
      return ["PER_TON", "PER_WAGON"];
    case "INTERCITY":
      return ["PER_CONTAINER", "PER_TON", "PER_WAGON", "PER_KM"];
    case "FIRST_MILE":
    case "LAST_MILE":
      return ["PER_CONTAINER", "PER_TON", "PER_KM", "FLAT"];
    default:
      return ["FLAT"];
  }
};

/**
 * Unit choices for the rate form. `cargoUnitOfMeasure` is how the bulk
 * commodity picked in the form is counted (PER_TON / PER_ITEM) — injected by
 * RuleEngineResourcePage, which is the layer that has the cargo type list.
 */
export const rateUnitOptions = (
  values: Record<string, unknown>,
  cargoUnitOfMeasure = "",
) => {
  const appliesTo = String(values.appliesTo ?? "");
  const trigger = appliesTo === "OTHER" ? String(values.trigger ?? "") : "ALWAYS";
  if (!appliesTo) return [];
  return allowedRateUnits(
    appliesTo,
    trigger,
    String(values.cargoKind ?? ""),
    cargoUnitOfMeasure,
  ).map(unitOption);
};

const CURRENCIES = [
  { label: "USD", value: "USD" },
  { label: "ETB", value: "ETB" },
];

const PRIORITY_CONFIG_TYPES = [
  { label: "Wagon count", value: "WAGON" },
  { label: "Payment currency", value: "CURRENCY" },
  { label: "Customs clearance", value: "CUSTOMS" },
];

const codeColumn = (key: string, header = "Code"): ResourceColumn => ({
  id: key,
  header,
  accessorKey: key,
  format: "code",
});

const activeColumn: ResourceColumn = {
  id: "isActive",
  header: "Status",
  accessorKey: "isActive",
  format: "activeBadge",
};

export const RULE_ENGINE_RESOURCES: RuleEngineResourceConfig[] = [
  {
    slug: "cargo-types",
    label: "Cargo Types",
    category: "configuration",
    subtitle: "Manage freight cargo classification and approval rules",
    searchPlaceholder: "Search cargo types by name or code...",
    supportsSearch: true,
    orderConfig: { field: "displayOrder", label: "Display order" },
    columns: [
      codeColumn("code"),
      { id: "cargoTypeName", header: "Name", accessorKey: "cargoTypeName" },
      { id: "unitOfMeasure", header: "Billed by", accessorKey: "unitOfMeasure" },
      {
        id: "requiresDirectorApproval",
        header: "Director approval",
        accessorKey: "requiresDirectorApproval",
        format: "boolean",
      },
      { id: "displayOrder", header: "Order", accessorKey: "displayOrder", format: "number" },
      activeColumn,
    ],
    formFields: [
      { name: "cargoTypeName", label: "Cargo type name", type: "text", required: true },
      {
        name: "unitOfMeasure",
        label: "Billed by",
        type: "select",
        optional: true,
        placeholder: "Not set (container/legacy cargo)",
        description:
          "Bulk storage/demurrage bills per ton for Tonnage cargo, per unit for Countable cargo (e.g. Machinery, Truck, Automobile, Livestock).",
        options: [
          { label: "Tonnage (per ton)", value: "PER_TON" },
          { label: "Countable (per item)", value: "PER_ITEM" },
        ],
      },
      {
        name: "parentGroupId",
        label: "Parent group",
        type: "select",
        optional: true,
        placeholder: "Select parent cargo type (optional)",
      },
      { name: "requiresDirectorApproval", label: "Requires director approval", type: "boolean" },
      { name: "hasLashing", label: "Charge lashing fee", type: "boolean" },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "container-types",
    label: "Container Types",
    category: "configuration",
    subtitle: "Configure container sizes",
    searchPlaceholder: "Search container types...",
    supportsSearch: true,
    orderConfig: { field: "displayOrder", label: "Display order" },
    columns: [
      codeColumn("code"),
      { id: "label", header: "Label", accessorKey: "label" },
      { id: "displayOrder", header: "#", accessorKey: "displayOrder", format: "number" },
      { id: "sizeFt", header: "Size (ft)", accessorKey: "sizeFt", format: "number" },
      activeColumn,
    ],
    formFields: [
      { name: "label", label: "Label", type: "text", required: true },
      { name: "sizeFt", label: "Size (ft)", type: "number", required: true },
      // Options injected at render from useWagonTypeOptions (RuleEngineResourcePage).
      {
        name: "wagonTypeIds",
        label: "Wagon types",
        type: "multiselect",
        required: true,
        description:
          "Wagon types that can carry this container during train scheduling (one container size per wagon at a time).",
        getInitialValue: (record) =>
          ((record.wagonTypes as { id: string }[] | undefined) ?? []).map((wt) => wt.id),
      },
      { name: "isOpenTop", label: "Open top", type: "boolean" },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "wagon-types",
    label: "Wagon Types",
    category: "configuration",
    subtitle: "Configure wagon classes used for capacity and train planning",
    searchPlaceholder: "Search wagon types by name or code...",
    // No supportsSearch: wagon-types is served by its own module, which does
    // not implement server-side search (unlike the 9 rule-engine resources).
    cardTitleKey: "name",
    columns: [
      codeColumn("code"),
      { id: "name", header: "Name", accessorKey: "name" },
      { id: "capacityTons", header: "Capacity (t)", accessorKey: "capacityTons", format: "number" },
      { id: "lengthMeters", header: "Length (m)", accessorKey: "lengthMeters", format: "number" },
      { id: "tareWeightTons", header: "Tare (t)", accessorKey: "tareWeightTons", format: "number" },
      {
        id: "supportedLoadTypes",
        header: "Load types",
        accessorKey: "supportedLoadTypes",
      },
      activeColumn,
    ],
    formFields: [
      { name: "code", label: "Code", type: "text", required: true },
      { name: "name", label: "Name", type: "text", required: true },
      { name: "capacityTons", label: "Capacity (tons)", type: "number", required: true },
      { name: "lengthMeters", label: "Length (meters)", type: "number", required: true },
      // The locomotive's pull limit is a GROSS limit, so capacity planning charges
      // `cargo + wagons × tare` against it. The API rejects a create without this.
      {
        name: "tareWeightTons",
        label: "Tare weight (tons)",
        type: "number",
        required: true,
        description: "Empty wagon weight — counts against the locomotive's pull limit alongside the cargo",
      },
      {
        name: "supportedLoadTypes",
        label: "Supported load types",
        type: "textarea",
        optional: true,
        placeholder: "CONTAINER, BULK",
      },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "truck-types",
    label: "Truck Types",
    category: "configuration",
    subtitle:
      "Configure the truck configurations vehicles are registered against — capacity and whether a trailer applies",
    searchPlaceholder: "Search truck types by name or code...",
    cardTitleKey: "name",
    columns: [
      codeColumn("code"),
      { id: "name", header: "Name", accessorKey: "name" },
      { id: "capacityTons", header: "Capacity (t)", accessorKey: "capacityTons", format: "number" },
      { id: "hasTrailer", header: "Has trailer", accessorKey: "hasTrailer" },
      activeColumn,
    ],
    formFields: [
      { name: "code", label: "Code", type: "text", required: true },
      { name: "name", label: "Name", type: "text", required: true },
      {
        name: "capacityTons",
        label: "Capacity (tons)",
        type: "number",
        optional: true,
        description: "Pre-fills the capacity of every vehicle registered on this type",
      },
      // Drives the trailer plate on vehicle registration: a rigid truck (Casoni)
      // has none, so registering one with a trailer plate is rejected.
      {
        name: "hasTrailer",
        label: "Pulls a trailer",
        type: "boolean",
        description: "Off for a rigid truck (e.g. Casoni) — its registration has no trailer plate",
      },
      { name: "description", label: "Description", type: "textarea", optional: true },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "yard-distances",
    label: "Yard Distances",
    category: "configuration",
    subtitle: "Rail distance between yard pairs — routes read their segment km from here",
    searchPlaceholder: "Search by yard name or code...",
    supportsSearch: true,
    cardTitleKey: "fromYardLabel",
    cardSubtitleKey: "toYardLabel",
    columns: [
      { id: "fromYardLabel", header: "From yard", accessorKey: "fromYardLabel" },
      { id: "toYardLabel", header: "To yard", accessorKey: "toYardLabel" },
      { id: "distanceKm", header: "Distance (km)", accessorKey: "distanceKm", format: "number" },
    ],
    formFields: [
      // Options injected at render from useYardOptions (RuleEngineResourcePage).
      { name: "fromYardId", label: "From yard", type: "select", required: true, placeholder: "Select yard" },
      { name: "toYardId", label: "To yard", type: "select", required: true, placeholder: "Select yard" },
      {
        name: "distanceKm",
        label: "Distance (km)",
        type: "number",
        required: true,
        description:
          "Symmetric — one entry covers both directions. Route segments between these yards use this value.",
      },
    ],
  },
  {
    slug: "priority-configs",
    label: "Priority Rules",
    category: "rules",
    subtitle: "Wagon-count, payment-currency, and customs scoring rules",
    searchPlaceholder: "Search priority rules...",
    supportsSearch: true,
    orderConfig: { field: "displayOrder", label: "Display order" },
    columns: [
      { id: "type", header: "Type", accessorKey: "type" },
      { id: "currency", header: "Currency", accessorKey: "currency" },
      { id: "minWagonCount", header: "Min wagons", accessorKey: "minWagonCount", format: "number" },
      { id: "maxWagonCount", header: "Max wagons", accessorKey: "maxWagonCount", format: "number" },
      { id: "scorePoints", header: "Points", accessorKey: "scorePoints", format: "number" },
      activeColumn,
    ],
    formFields: [
      {
        name: "type",
        label: "Type",
        type: "select",
        required: true,
        options: PRIORITY_CONFIG_TYPES,
        placeholder: "Wagon count or payment currency",
      },
      {
        name: "currency",
        label: "Currency",
        type: "select",
        optional: true,
        options: [{ label: "None", value: RULE_ENGINE_SELECT_NONE }, ...CURRENCIES],
        placeholder: "Select a currency",
        hideWhen: { field: "type", equals: ["WAGON", "CUSTOMS"] },
      },
      {
        name: "minWagonCount",
        label: "Min wagon count",
        type: "number",
        required: true,
        disabled: true,
        description: "Auto-filled — continues the previous range for the selected type",
      },
      {
        name: "maxWagonCount",
        label: "Max wagon count",
        type: "number",
        required: true,
        description: "No upper limit — must be at least the min wagon count",
      },
      { name: "scorePoints", label: "Score points", type: "number", required: true },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "service-types",
    label: "Service Types",
    category: "configuration",
    subtitle: "Freight service offerings and booking options",
    searchPlaceholder: "Search service types...",
    supportsSearch: true,
    orderConfig: { field: "displayOrder", label: "Display order" },
    columns: [
      codeColumn("code"),
      { id: "serviceName", header: "Service name", accessorKey: "serviceName" },
      { id: "displayOrder", header: "#", accessorKey: "displayOrder", format: "number" },
      activeColumn,
    ],
    formFields: [
      { name: "serviceName", label: "Service name", type: "text", required: true },
      { name: "description", label: "Description", type: "textarea" },
      { name: "canBeBookedAlone", label: "Can be booked alone", type: "boolean" },
      { name: "includesFirstMile", label: "Includes first mile", type: "boolean" },
      { name: "includesLastMile", label: "Includes last mile", type: "boolean" },
      { name: "includesCustoms", label: "Includes customs", type: "boolean" },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "weight-limit-rules",
    label: "Weight Limit Rules",
    category: "rules",
    subtitle: "VGM limits by container and trade direction",
    searchPlaceholder: "Search weight limit rules...",
    supportsSearch: true,
    cardTitleKey: "containerType",
    cardSubtitleKey: "tradeDirection",
    columns: [
      {
        id: "containerType",
        header: "Container",
        accessorKey: "containerType",
        format: "entityLabel",
      },
      { id: "tradeDirection", header: "Direction", accessorKey: "tradeDirection" },
      { id: "maxVgmTons", header: "Max VGM (t)", accessorKey: "maxVgmTons", format: "number" },
      {
        id: "maxCapacityTons",
        header: "Max capacity (t)",
        accessorKey: "maxCapacityTons",
        format: "number",
      },
    ],
    formFields: [
      {
        name: "containerTypeId",
        label: "Container type",
        type: "select",
        required: true,
        placeholder: "Select container type",
      },
      {
        name: "tradeDirection",
        label: "Trade direction",
        type: "select",
        required: true,
        options: TRADE_DIRECTIONS,
      },
      { name: "maxVgmTons", label: "Max VGM (tons)", type: "number", required: true },
      {
        name: "maxCapacityTons",
        label: "Max capacity (tons)",
        type: "number",
        optional: true,
        description:
          "Hard ceiling — a booking whose line weight exceeds this cannot be created at all. Leave empty for no ceiling (overweight surcharge only).",
      },
    ],
  },
  {
    slug: "yards",
    label: "Yards",
    category: "configuration",
    subtitle: "Terminal and yard locations",
    searchPlaceholder: "Search yards...",
    supportsSearch: true,
    orderConfig: { field: "displayOrder", label: "Display order" },
    columns: [
      codeColumn("code"),
      { id: "label", header: "Label", accessorKey: "label" },
      { id: "country", header: "Country", accessorKey: "country" },
      {
        id: "hasFacility",
        header: "Facility",
        accessorKey: "hasFacility",
        format: "boolean",
      },
      { id: "displayOrder", header: "Order", accessorKey: "displayOrder", format: "number" },
      activeColumn,
    ],
    formFields: [
      { name: "label", label: "Label", type: "text", required: true },
      {
        name: "country",
        label: "Country",
        type: "select",
        required: true,
        options: YARD_COUNTRIES,
      },
      {
        name: "hasFacility",
        label: "Has load/unload facility",
        type: "boolean",
        description:
          "This yard can load and unload cargo. Intercity bookings can only be loaded at their origin and unloaded at their destination when it is a facility.",
      },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "shipping-lines",
    label: "Shipping Lines",
    category: "configuration",
    subtitle: "Shipping line codes and pricing mappings",
    searchPlaceholder: "Search shipping lines...",
    supportsSearch: true,
    columns: [
      codeColumn("code"),
      { id: "label", header: "Label", accessorKey: "label" },
      { id: "mappedToCode", header: "Mapped to", accessorKey: "mappedToCode" },
      {
        id: "showExtraFeeNotice",
        header: "Extra fee notice",
        accessorKey: "showExtraFeeNotice",
        format: "boolean",
      },
      activeColumn,
    ],
    formFields: [
      { name: "code", label: "Code", type: "text", required: true },
      { name: "label", label: "Label", type: "text", required: true },
      { name: "mappedToCode", label: "Mapped to code", type: "text" },
      { name: "showExtraFeeNotice", label: "Show extra fee notice", type: "boolean" },
      { name: "isActive", label: "Active", type: "boolean" },
    ],
  },
  {
    slug: "rates",
    label: "Rates",
    category: "rules",
    cardTitleKey: "appliesTo",
    cardSubtitleKey: "currency",
    subtitle: "Freight rates and approval workflow",
    searchPlaceholder: "Search rates by type or status...",
    supportsSearch: true,
    // Category tabs — each filters server-side by appliesTo / trigger.
    listTabs: [
      { key: "all", label: "All", filters: {} },
      { key: "container", label: "Container", filters: { appliesTo: "CONTAINER" } },
      { key: "bulk", label: "Bulk", filters: { appliesTo: "BULK" } },
      { key: "intercity", label: "Intercity", filters: { appliesTo: "INTERCITY" } },
      {
        key: "trucking",
        label: "First / Last mile",
        filters: { appliesTo: "FIRST_MILE,LAST_MILE" },
      },
      {
        key: "customs",
        label: "Customs clearance",
        filters: { trigger: "CUSTOMS_CLEARANCE" },
      },
      {
        key: "return",
        label: "Container return",
        filters: { trigger: "WITH_RETURN" },
      },
      {
        key: "surcharges",
        label: "Surcharges",
        filters: {
          appliesTo: "OTHER",
          trigger:
            "HAZARDOUS,OVERWEIGHT,REEFER,SHIPPING_LINE,CONSOLIDATION,LASHING,CANCELLATION,PIL_EXTRA_FEE",
        },
      },
    ],
    columns: [
      { id: "appliesTo", header: "Applies to", accessorKey: "appliesTo", format: "code" },
      { id: "trigger", header: "Trigger", accessorKey: "trigger" },
      // Base freight is priced per leg, so the route is what tells two otherwise
      // identical rates apart. Surcharges have no leg and render as "—".
      { id: "originYard", header: "From", accessorKey: "originYard", format: "entityLabel" },
      {
        id: "destinationYard",
        header: "To",
        accessorKey: "destinationYard",
        format: "entityLabel",
      },
      { id: "rateValue", header: "Value", accessorKey: "rateValue", format: "currency" },
      { id: "rateUnit", header: "Unit", accessorKey: "rateUnit" },
      { id: "status", header: "Status", accessorKey: "status", format: "rateStatus" },
    ],
    formFields: [
      {
        name: "appliesTo",
        label: "Applies to",
        type: "select",
        required: true,
        options: RATE_APPLIES_TO,
        description:
          "Pick what this rate is for. Bulk/Container/Intercity are base freight; Other is an auto-applied surcharge.",
      },
      // ── Surcharge trigger — only when Applies to = Other ──────────────────
      {
        name: "trigger",
        label: "Surcharge trigger",
        type: "select",
        required: true,
        options: RATE_TRIGGERS,
        placeholder: "What makes this surcharge apply?",
        showWhen: { field: "appliesTo", equals: ["OTHER"] },
      },
      // ── Trade direction — Bulk & Container base freight, plus the route-
      // scoped surcharges (customs clearance; empty-container return, which is
      // import-only for now so export is not offered) ────────────────────────
      {
        name: "tradeDirection",
        label: "Trade direction",
        type: "select",
        required: true,
        optionsFromValues: (v: Record<string, unknown>) =>
          String(v.trigger ?? "") === "WITH_RETURN" &&
          String(v.appliesTo ?? "") === "OTHER"
            ? TRADE_DIRECTIONS.filter((d) => d.value === "IMPORT")
            : TRADE_DIRECTIONS.filter((d) => d.value !== "BOTH"),
        showIf: (v) =>
          ["BULK", "CONTAINER"].includes(String(v.appliesTo ?? "")) ||
          (String(v.appliesTo ?? "") === "OTHER" &&
            ["CUSTOMS_CLEARANCE", "WITH_RETURN", "LASHING"].includes(
              String(v.trigger ?? ""),
            )),
      },
      // ── Cargo kind — customs clearance is priced separately for containers
      // (one rate per container type) and bulk ───────────────────────────────
      {
        name: "cargoKind",
        label: "Cargo kind",
        type: "select",
        required: true,
        options: INTERCITY_KINDS,
        placeholder: "Is this fee for containers or bulk?",
        description:
          "Container fees bill per box or wagon (one rate per container type); bulk fees bill per ton or wagon.",
        showIf: (v) =>
          v.appliesTo === "OTHER" && v.trigger === "CUSTOMS_CLEARANCE",
        // Not a stored column: a container fee carries its containerTypeId, a
        // bulk fee carries none.
        getInitialValue: (record) =>
          record.containerTypeId ? "CONTAINER" : "BULK",
      },
      // ── Container type — a container fee names the type it covers ─────────
      {
        name: "containerTypeId",
        label: "Container type",
        type: "select",
        required: true,
        placeholder: "Which container type this fee covers",
        showIf: (v) =>
          v.appliesTo === "OTHER" &&
          v.trigger === "CUSTOMS_CLEARANCE" &&
          v.cargoKind === "CONTAINER",
      },
      // ── Bulk cargo type — the bulk customs fee names its commodity ────────
      {
        name: "cargoTypeId",
        label: "Bulk cargo type",
        type: "select",
        required: true,
        placeholder: "Which bulk commodity this fee covers",
        showIf: (v) =>
          v.appliesTo === "OTHER" &&
          v.trigger === "CUSTOMS_CLEARANCE" &&
          v.cargoKind === "BULK",
      },
      // ── Bulk cargo type — lashing is bulk-only; may narrow to one leaf
      // commodity (specific wins over the commodity-wide catch-all) ──────────
      {
        name: "cargoTypeId",
        label: "Bulk cargo type",
        type: "select",
        optional: true,
        placeholder: "All lashing commodities (optional)",
        description:
          "Leave empty to cover every lashing commodity; a commodity-specific rate wins over the catch-all.",
        showIf: (v) =>
          v.appliesTo === "OTHER" && v.trigger === "LASHING",
      },
      // ── Cargo kind — Intercity only (import/export get it from appliesTo) ─
      {
        name: "intercityKind",
        label: "Cargo type",
        type: "select",
        required: true,
        options: INTERCITY_KINDS,
        placeholder: "Is this rate for containers or bulk?",
        description: "Intercity prices containers and bulk differently — pick which this covers.",
        showWhen: { field: "appliesTo", equals: ["INTERCITY"] },
        // Not a stored column: an existing rate records its kind in the rateType
        // the API derived (INTERCITY_BULK / INTERCITY_CONTAINER).
        getInitialValue: (record) =>
          record.rateType === "INTERCITY_BULK" ? "BULK" : "CONTAINER",
      },
      // ── Container type — Container freight, container-kind intercity, and
      // the empty-container return surcharge (20ft vs 40ft price differently) ─
      {
        name: "containerTypeId",
        label: "Container type",
        type: "select",
        optional: true,
        placeholder: "Select container type (optional)",
        showIf: (v) =>
          v.appliesTo === "CONTAINER" ||
          (v.appliesTo === "INTERCITY" && v.intercityKind === "CONTAINER") ||
          (v.appliesTo === "OTHER" && v.trigger === "WITH_RETURN"),
      },
      // ── Bulk cargo (leaf commodity) — Bulk freight, and bulk-kind intercity ─
      {
        name: "cargoTypeId",
        label: "Bulk cargo type",
        type: "select",
        optional: true,
        placeholder: "Select bulk commodity (optional)",
        showIf: (v) =>
          v.appliesTo === "BULK" ||
          (v.appliesTo === "INTERCITY" && v.intercityKind === "BULK"),
      },
      // ── The leg this rate prices — base freight only ──────────────────────
      // Options are narrowed to the countries the direction allows (import
      // starts in Djibouti, export in Ethiopia, intercity stays in Ethiopia);
      // see RuleEngineResourcePage, which injects the yard lists.
      {
        name: "originYardId",
        label: "Origin yard",
        type: "select",
        required: true,
        placeholder: "Where the leg starts",
        showIf: isRouteScopedRate,
      },
      {
        name: "destinationYardId",
        label: "Destination yard",
        type: "select",
        required: true,
        placeholder: "Where the leg ends",
        showIf: isRouteScopedRate,
      },
      { name: "rateValue", label: "Rate value", type: "number", required: true, suffix: "USD" },
      // Unit choices are driven by the rate shape (appliesTo + trigger). Overweight
      // is always per excess ton, so the unit field is hidden for it — the API
      // forces PER_TON regardless.
      {
        name: "rateUnit",
        label: "Rate unit",
        type: "select",
        required: true,
        optionsFromValues: rateUnitOptions,
        description:
          "Weighting basis — options depend on what the rate applies to, and for bulk on how the picked commodity is counted (per ton or per item).",
        hideWhen: { field: "trigger", equals: ["OVERWEIGHT"] },
      },
    ],
  },
  {
    slug: "approval-rules",
    label: "Approval Rules",
    category: "rules",
    cardTitleKey: "actionLabel",
    cardSubtitleKey: "requiredRole",
    subtitle: "Multi-step booking approval chain",
    searchPlaceholder: "Search approval rules...",
    supportsSearch: true,
    orderConfig: {
      field: "stepOrder",
      scopeField: "requiresDirectorApproval",
      label: "Step order",
    },
    columns: [
      {
        id: "requiresDirectorApproval",
        header: "Director chain",
        accessorKey: "requiresDirectorApproval",
        format: "boolean",
      },
      { id: "stepOrder", header: "Step", accessorKey: "stepOrder", format: "number" },
      { id: "requiredRole", header: "Role", accessorKey: "requiredRole" },
      { id: "actionLabel", header: "Action", accessorKey: "actionLabel" },
      { id: "blocksRole", header: "Blocks", accessorKey: "blocksRole" },
    ],
    formFields: [
      { name: "requiresDirectorApproval", label: "Requires director approval chain", type: "boolean" },
      {
        name: "requiredRole",
        label: "Required role",
        type: "select",
        required: true,
        // Replaced at render time with live IAM position types (+ legacy values).
        options: LEGACY_APPROVAL_ROLES,
      },
      { name: "actionLabel", label: "Action label", type: "text", required: true },
      {
        name: "blocksRole",
        label: "Blocks role",
        type: "select",
        optional: true,
        // Replaced at render time with live IAM position types (+ legacy values).
        options: [{ label: "None", value: RULE_ENGINE_SELECT_NONE }, ...LEGACY_APPROVAL_ROLES],
      },
    ],
  },
];

export const RULE_ENGINE_RESOURCE_MAP = Object.fromEntries(
  RULE_ENGINE_RESOURCES.map((r) => [r.slug, r]),
) as Record<RuleEngineResourceSlug, RuleEngineResourceConfig>;

export const getRuleEngineResource = (slug: string): RuleEngineResourceConfig | undefined =>
  RULE_ENGINE_RESOURCE_MAP[slug as RuleEngineResourceSlug];

export const ruleEngineResourcePath = (slug: RuleEngineResourceSlug): string => {
  const resource = RULE_ENGINE_RESOURCE_MAP[slug];
  return `${RULE_ENGINE_CATEGORY_BASE_PATH[resource.category]}/${slug}`;
};

export const getCategorySidebarChildren = (
  category: RuleEngineNavCategory,
): SidebarItem[] =>
  RULE_ENGINE_RESOURCES.filter((r) => r.category === category).map((r) => ({
    label: r.label,
    href: ruleEngineResourcePath(r.slug),
    permission: ruleEngineViewKey(r.slug),
  }));

export const DEFAULT_CONFIGURATION_SLUG: RuleEngineResourceSlug = "cargo-types";
export const DEFAULT_RULES_SLUG: RuleEngineResourceSlug = "priority-configs";

/** @deprecated Use DEFAULT_CONFIGURATION_SLUG */
export const DEFAULT_RULE_ENGINE_SLUG = DEFAULT_CONFIGURATION_SLUG;
