/**
 * lib/url-conventions.ts — Single source of truth for the bi-strata API URL
 * conventions. Imported by BOTH backend scaffolders (`scaffold-controller`,
 * `scaffold-screen-controller`) AND the frontend `scaffold-api-client`, plus
 * the static parity audit `audit-dev-wire`.
 *
 * Two strata exist; nothing else is legal:
 *   - **Integration**  /api/v1/integration/{plural-kebab}     (machine-to-machine CRUD)
 *   - **Screen-driven** /api/screens/{plural-kebab}/{view}    (UI-facing, shaped by pagespec)
 *
 * Centralising the two prefixes here makes drift mathematically impossible —
 * the route emitted by the C# controller and the URL called by the TS service
 * derive from the same constant.
 */

import { toKebabCase } from './string-utils.js'

export const INTEGRATION_STRATUM_PREFIX = '/api/v1/integration'
export const SCREEN_STRATUM_PREFIX = '/api/screens'

export type Stratum = 'direct' | 'integration' | 'screens' | 'unknown'

/**
 * Build the direct-mode base path for an entity — the standard SmartStack
 * controller route: `/api/{appCode}/{module}/{section}`.
 *
 *   buildDirectRoute('gaf', 'referentiels', 'employes')
 *     → '/api/gaf/referentiels/employes'
 */
export function buildDirectRoute(appCode: string, module: string, sectionKebab: string): string {
  return `/api/${appCode.toLowerCase()}/${module}/${sectionKebab}`
}

/**
 * Build the integration-stratum base path for an entity.
 * Used by `scaffold-controller` and by `scaffold-api-client` in legacy mode.
 *
 *   buildIntegrationRoute('demandes')      → '/api/v1/integration/demandes'
 *   buildIntegrationRoute('multi-words')   → '/api/v1/integration/multi-words'
 */
export function buildIntegrationRoute(pluralKebab: string): string {
  return `${INTEGRATION_STRATUM_PREFIX}/${pluralKebab}`
}

/**
 * Build the screen-driven base path for an entity.
 * Used by `scaffold-screen-controller` and by `scaffold-api-client` in
 * `useScreens=true` mode.
 *
 *   buildScreenRoute('demandes')           → '/api/screens/demandes'
 */
export function buildScreenRoute(pluralKebab: string): string {
  return `${SCREEN_STRATUM_PREFIX}/${pluralKebab}`
}

/**
 * Per-view suffix appended to a screen-driven base path.
 * Used by both sides so that the controller's `[HttpVerb("<suffix>")]` and
 * the api-client's URL string come from the same lookup.
 *
 *   buildScreenViewPath('list')      → '/list'
 *   buildScreenViewPath('detail')    → '/detail/{id:guid}'
 *   buildScreenViewPath('form')      → '/form'
 *   buildScreenViewPath('dashboard') → '/dashboard/consolidated'
 *
 * Hub views (`section-home`, `app-home`, `module-home`) deliberately have no
 * suffix — they are Slot containers that emit no API call.
 */
export type ScreenView = 'list' | 'detail' | 'form' | 'dashboard'
export function buildScreenViewPath(view: ScreenView): string {
  switch (view) {
    case 'list':
      return '/list'
    case 'detail':
      return '/detail/{id:guid}'
    case 'form':
      return '/form'
    case 'dashboard':
      return '/dashboard/consolidated'
  }
}

/**
 * Compute the URL-segment plural for an entity name. PascalCase → kebab-case
 * with proper handling of consecutive uppercase letters (`HRDepartment` →
 * `hr-department`). Equivalent across all scaffolders — never reimplement.
 */
export function pluralSegment(pluralName: string): string {
  return toKebabCase(pluralName)
}

/**
 * Canonicalise an arbitrary route literal (as emitted on either side) into its
 * stratum + remainder. Used by `audit-dev-wire` to compare frontend calls and
 * backend routes on equal ground.
 *
 *   canonicaliseRoute('/api/v1/integration/demandes/lookup')
 *     → { stratum: 'integration', rest: 'demandes/lookup' }
 *   canonicaliseRoute('/api/screens/demandes/dashboard/consolidated')
 *     → { stratum: 'screens', rest: 'demandes/dashboard/consolidated' }
 *   canonicaliseRoute('/api/affaires/accueil/dashboard')
 *     → { stratum: 'unknown', rest: 'affaires/accueil/dashboard' }
 *
 * The `unknown` stratum is the early-warning signal that something has drifted
 * — every legal URL in the generated app falls under one of the two known
 * prefixes.
 */
export function canonicaliseRoute(raw: string): { stratum: Stratum; rest: string } {
  const trimmed = raw.replace(/^\/+/, '/')
  if (trimmed.startsWith(`${INTEGRATION_STRATUM_PREFIX}/`)) {
    return { stratum: 'integration', rest: trimmed.slice(INTEGRATION_STRATUM_PREFIX.length + 1) }
  }
  if (trimmed === INTEGRATION_STRATUM_PREFIX) {
    return { stratum: 'integration', rest: '' }
  }
  if (trimmed.startsWith(`${SCREEN_STRATUM_PREFIX}/`)) {
    return { stratum: 'screens', rest: trimmed.slice(SCREEN_STRATUM_PREFIX.length + 1) }
  }
  if (trimmed === SCREEN_STRATUM_PREFIX) {
    return { stratum: 'screens', rest: '' }
  }
  return { stratum: 'unknown', rest: trimmed.replace(/^\/?(?:api\/)?/, '') }
}

/**
 * Build the route segment for a single custom action on either stratum.
 * The screen-driven controller emits this same segment under its
 * `[Route("api/screens/{plural}")]` class-level attribute.
 *
 *   buildCustomActionPath({ scope: 'row',    code: 'archive' })           → 'detail/{id:guid}/archive'
 *   buildCustomActionPath({ scope: 'bulk',   code: 'export' })            → 'bulk/export'
 *   buildCustomActionPath({ scope: 'header', code: 'sync-from-pce' })     → 'sync-from-pce'
 *
 * The `stratum` parameter only affects the row-scope segment — the integration
 * stratum uses `{id:guid}/<code>` (no `detail` prefix) while the screen
 * stratum prefixes with `detail/` so the URL grouping mirrors the GET detail
 * endpoint. This matches what `scaffold-controller` and
 * `scaffold-screen-controller` already emit today.
 */
export function buildCustomActionPath(args: {
  scope: 'row' | 'bulk' | 'header'
  code: string
  stratum?: Stratum
}): string {
  const { scope, code, stratum = 'integration' } = args
  if (scope === 'row') {
    return stratum === 'screens' ? `detail/{id:guid}/${code}` : `{id:guid}/${code}`
  }
  if (scope === 'bulk') return `bulk/${code}`
  return code
}
