/* Meridian — the route table.
   Deliberately NOT routes: the notification panel, the ⌘K palette, the row
   menus, the refund and reject confirm dialogs, the period scope control, the
   payments and payouts tabs, the card issuing dialog, the expense query dialog
   and the invite dialog. They are states of a screen, not destinations — a
   breadcrumb that wants one of them is a bug in the screen, not a missing route.

   Every route in this table has a screen behind it, and every entity the
   product lists now has the action that creates it (AGENTS §5): a customer, a
   payout and a payment each have a registered `/new` form, a card is issued
   through a staged dialog from /cards, and a teammate is invited through one
   from /people. A dispute has no create action — a chargeback arrives from the
   card network, never from this desk — and the disputes screen says so.

   Eleven top-level destinations, dense record work and four per-destination
   counts, so this product runs the SIDEBAR shell with TWO groups: the money
   moving through the platform, and the workspace doing the moving. Settings,
   the profile and the auth screens are registered off the sidebar and reached
   from the account menu. */

const MERIDIAN_NAV = [
  /* Group: Money. */
  { path: "/", label: "Dashboard", icon: "layout-dashboard", group: "Money" },
  { path: "/payments", label: "Payments", icon: "arrow-down-left", group: "Money" },
  { path: "/payouts", label: "Payouts", icon: "arrow-up-right", badge: "payoutsApprovable", group: "Money" },
  { path: "/disputes", label: "Disputes", icon: "shield-alert", badge: "disputesNeedingEvidence", group: "Money" },
  { path: "/balances", label: "Balances", icon: "wallet", group: "Money" },
  { path: "/reports", label: "Reports", icon: "trending-up", group: "Money" },

  /* Group: Workspace — our own spend, the companies on the other side of it,
     the people here, and what they are saying to each other. */
  { path: "/expenses", label: "Expenses", icon: "receipt", badge: "expensesToReview", group: "Workspace" },
  { path: "/cards", label: "Cards", icon: "credit-card", group: "Workspace" },
  { path: "/customers", label: "Customers", icon: "building-2", group: "Workspace" },
  { path: "/people", label: "People", icon: "users", group: "Workspace" },
  { path: "/activity", label: "Activity", icon: "message-square", badge: "notesAwaitingReply", group: "Workspace" },

  /* Registered, not in the nav. */
  { path: "/payments/new", label: "New payment", parent: "/payments", offSidebar: true },
  { path: "/payouts/new", label: "New payout", parent: "/payouts", offSidebar: true },
  { path: "/disputes/:id", label: "Dispute", parent: "/disputes", offSidebar: true },
  { path: "/cards/:id", label: "Card", parent: "/cards", offSidebar: true },
  { path: "/customers/new", label: "New customer", parent: "/customers", offSidebar: true },
  { path: "/customers/:id", label: "Customer", parent: "/customers", offSidebar: true },
  { path: "/people/:id", label: "Person", parent: "/people", offSidebar: true },
  { path: "/settings", label: "Workspace settings", offSidebar: true },
  { path: "/settings/profile", label: "Your profile", parent: "/settings", offSidebar: true },
  { path: "/settings/notifications", label: "Notification preferences", parent: "/settings", offSidebar: true },
  { path: "/settings/spend-controls", label: "Spend controls", parent: "/settings", offSidebar: true },
  { path: "/settings/team", label: "Team and approvals", parent: "/settings", offSidebar: true },
  { path: "/settings/billing", label: "Plan and billing", parent: "/settings", offSidebar: true },

  /* Auth namespace — excluded from the shell nav; no product chrome. Six
     screens, one flow: sign in → the 2FA challenge → the product. Each is
     registered because a person can arrive at any of them cold, from a link. */
  { path: "/signin", label: "Sign in", offSidebar: true },
  { path: "/two-factor", label: "Two-factor challenge", parent: "/signin", offSidebar: true },
  { path: "/verify-code", label: "Sign in with a code", parent: "/signin", offSidebar: true },
  { path: "/forgot-password", label: "Forgot password", parent: "/signin", offSidebar: true },
  { path: "/reset-password", label: "Set a new password", parent: "/signin", offSidebar: true },
  { path: "/signout", label: "Sign out", offSidebar: true },
];

const MERIDIAN_ROUTES = indexRoutes(MERIDIAN_NAV);

/* Projections the shell renders — derived by filtering the tree, never retyped.
   Two groups, so §6.3's "groups earn their labels" gives both one. */
const MERIDIAN_SIDEBAR = ["Money", "Workspace"].map((label) => ({
  label: label,
  items: MERIDIAN_NAV.filter((r) => !r.offSidebar && r.group === label),
}));

const MERIDIAN_ACCOUNT_MENU = [
  MERIDIAN_ROUTES["/settings/profile"],
  MERIDIAN_ROUTES["/settings"],
  MERIDIAN_ROUTES["/settings/spend-controls"],
  MERIDIAN_ROUTES["/settings/team"],
  MERIDIAN_ROUTES["/settings/notifications"],
  MERIDIAN_ROUTES["/settings/billing"],
  MERIDIAN_ROUTES["/signout"],
];

/* Paths that render without product chrome (AGENTS §7.1). */
const MERIDIAN_AUTH_PATHS = ["/signin", "/two-factor", "/verify-code", "/forgot-password", "/reset-password", "/signout"];

/* /cards/:id → /cards/crd_4471. The breadcrumb and every nested row use it, so
   no screen builds a path by concatenation. */
const resolvePath = (pattern, params) => pattern.replace(/:([^/]+)/g, (_, key) => (params && params[key] != null ? params[key] : ":" + key));

/* A note names the record it was written on, and the mentions queue opens it.
   Only record types that HAVE a screen can carry notes, so this never resolves
   to a route that does not exist. */
const RECORD_PATTERNS = { dispute: "/disputes/:id", card: "/cards/:id", customer: "/customers/:id", member: "/people/:id" };
const recordRoute = (record) => resolvePath(RECORD_PATTERNS[record.type], { id: record.id });

/* The preview menu's page list — this table read whole and grouped, never
   retyped, with the parameterised routes resolved against the fixture so the
   link lands on a real record rather than on ":id". A pattern with no fixture
   example is left out rather than offered as a link resolving nowhere. */
const MERIDIAN_PAGES = (data) => {
  const dispute = data.disputes[0], card = data.cards[0], customer = data.customers[0], person = data.members[0];
  return templatePages(MERIDIAN_NAV, MERIDIAN_AUTH_PATHS, {
    "/disputes/:id": dispute ? resolvePath("/disputes/:id", { id: dispute.id }) : null,
    "/cards/:id": card ? resolvePath("/cards/:id", { id: card.id }) : null,
    "/customers/:id": customer ? resolvePath("/customers/:id", { id: customer.id }) : null,
    "/people/:id": person ? resolvePath("/people/:id", { id: person.id }) : null,
  });
};

Object.assign(window, { MERIDIAN_NAV, MERIDIAN_ROUTES, MERIDIAN_SIDEBAR, MERIDIAN_ACCOUNT_MENU, MERIDIAN_AUTH_PATHS, MERIDIAN_PAGES, resolvePath, recordRoute });
