/**
 * Shared settings interfaces used across the modeler application.
 *
 * These types describe the Drupal-provided settings object that is passed
 * into the React application at initialization and threaded through
 * components and hooks.
 */

/**
 * Component type names used in context definitions.
 */
export type ContextComponentType = 'start' | 'subprocess' | 'swimlane' | 'element' | 'link' | 'gateway' | 'annotation';

/**
 * A dependency constraint: a plugin can only be used when at least one of
 * its listed predecessor plugins is present in the current workflow.
 */
export interface ContextDependency {
  type: ContextComponentType;
  id: string;
}

/**
 * Dependency definitions delivered via drupalSettings.modeler_api.dependencies.
 *
 * Top-level keys are component type names (e.g. `"link"`, `"element"`).
 * Each value is a record keyed by plugin ID, mapping to an array of
 * predecessor dependency constraints.
 *
 * Matches the schema defined in dependency_list.schema.json.
 */
export type ModelerDependencies = Partial<
  Record<ContextComponentType, Record<string, ContextDependency[]>>
>;

/**
 * Plugins allowed for a single component type within a context.
 */
interface ContextComponentEntry {
  plugins: string[];
}

/**
 * A resolved modeler API context for a given model owner.
 * Matches the schema defined in context_list.schema.json.
 */
export interface ModelerContext {
  id: string;
  topic: string;
  model_owner: string;
  components: Partial<Record<ContextComponentType, ContextComponentEntry>>;
}

/**
 * Model-owner-provided labels for the core component types.
 *
 * The modeler itself is model-owner agnostic — different owners may call
 * their components by different names (e.g. "Event" vs "Trigger", "Action"
 * vs "Task").  This map lets the backend supply the correct terminology.
 *
 * Keys correspond to the internal node/edge types used by the modeler.
 * All fields are optional; missing labels fall back to generic defaults
 * (see `DEFAULT_COMPONENT_LABELS` in `componentUtils.ts`).
 */
export interface ComponentLabels {
  /** Label for start/event nodes (default: "Start"). */
  start?: string;
  /** Label for element/action nodes (default: "Element"). */
  element?: string;
  /** Label for link/condition edges (default: "Link"). */
  link?: string;
  /** Label for gateway nodes (default: "Gateway"). */
  gateway?: string;
  /** Label for subprocess nodes (default: "Subprocess"). */
  subprocess?: string;
}

/**
 * Settings specific to the modeler UI (drupalSettings.modeler).
 */
interface ModelerSettings {
  stayInContextOnClose?: boolean;
  replayData?: any[];
  modelId?: string;
  components?: any[];
  modelData?: any;
  selectComponentId?: string;
  selectContextId?: string;
  /**
   * Key/value pairs provided via query parameter that should be used as
   * default configuration values for newly added components (nodes and
   * edge conditions). When a config form field key matches a key in this
   * map, the contextConfig value is applied automatically.
   */
  setContextConfig?: Record<string, string>;
  /**
   * When true the modeler runs in standalone (viewer) mode without a
   * Drupal backend.  The canvas is read-only, editing UI is hidden,
   * and configuration forms are read from `configForms` instead of
   * being fetched from the backend.
   */
  standalone?: boolean;
  /**
   * Pre-loaded configuration form schemas keyed by plugin ID (for nodes)
   * or condition plugin ID (for edges).  Only used in standalone mode.
   * Each value is the `form` array normally returned by the backend
   * config_url endpoint.
   */
  configForms?: Record<string, any[]>;
}

/**
 * A single global token entry as provided by the Drupal backend.
 */
export interface GlobalToken {
  name: string;
  description?: string;
  dynamic?: boolean;
  type?: string;
  'raw token': string;
  token: string;
  value?: any;
  parent?: string;
  children?: Record<string, GlobalToken>;
}

/**
 * Owner-provided component definitions keyed by category.
 */
interface OwnerComponents {
  [category: string]: any[];
}

/**
 * Granular permissions provided by the modeler API via
 * `drupalSettings.modeler_api.permissions`.
 *
 * Each key corresponds to a feature the backend can enable or disable.
 * Values default to `true` when omitted.
 */
export interface ModelerPermissions {
  /** Whether the user may edit model metadata (label, version, tags, …). */
  'edit metadata'?: boolean;
  /** Whether the user may switch the active context. */
  'switch context'?: boolean;
  /** Whether the user may edit a template model. */
  'edit template'?: boolean;
  /** Whether the user may mark a model as template. */
  'create template'?: boolean;
  /** Whether the user may trigger test executions. */
  'test'?: boolean;
  /** Whether the user may use the replay panel / load replay data. */
  'replay'?: boolean;
}

/**
 * API endpoint URLs and model metadata (drupalSettings.modeler_api).
 */
interface ModelerApiSettings {
  token_url?: string;
  save_url?: string;
  config_url?: string;
  replay_url?: string;
  test_url?: string;
  collection_url?: string;
  export_url?: string;
  export_recipe_url?: string;
  isNew?: boolean;
  readOnly?: boolean;
  /**
   * Granular permissions from the backend.  Missing keys default to `true`.
   */
  permissions?: ModelerPermissions;
  favorite_components?: Record<number, string[]>;
  contexts?: ModelerContext[];
  /**
   * Dependency definitions that constrain which plugins can be used based
   * on which predecessor plugins are present in the current workflow.
   * Keyed by component type, then by plugin ID.
   */
  dependencies?: ModelerDependencies;
  /**
   * Global tokens available across the entire site, keyed by raw token
   * string (e.g. `[current-date:custom:?]`). Each entry has a `name`,
   * optional `description`, `token` (without prefix), `raw token`,
   * `value`, and optionally `children` (recursive same structure).
   */
  global_tokens?: Record<string, GlobalToken>;
  /**
   * Template tokens defined by the current template model, keyed by raw
   * token string. Uses the same recursive `GlobalToken` structure.
   * Only present when the model is a template (`metadata.template` is true).
   */
  template_tokens?: Record<string, GlobalToken>;
  metadata?: {
    version?: string;
    label?: string;
    description?: string;
    storage?: string;
    executable?: boolean;
    template?: boolean;
    tags?: string[];
    changelog?: string;
  };
  /**
   * Model-owner-provided labels for the core component types.
   * Allows different model owners to use their own terminology
   * (e.g. "Event" vs "Trigger", "Action" vs "Task").
   */
  component_labels?: ComponentLabels;
}

/**
 * Top-level settings object passed from Drupal into the React app.
 */
export interface Settings {
  modeler?: ModelerSettings;
  modeler_api?: ModelerApiSettings;
  ownerComponents?: OwnerComponents;
}

/**
 * Drupal AJAX helper object injected by the host page.
 */
export interface DrupalAjax {
  ajax: (settings: any) => any;
  t?: (text: string) => string;
}

/**
 * Edge order information used to display and reorder edges from the same source node.
 */
export interface EdgeOrderInfo {
  pathX?: number;
  pathY?: number;
  order: number;
  totalEdges: number;
  sourceNodeId?: string;
}

/**
 * Base data interface shared by all edge component types (Default, Condition, Annotation).
 */
export interface BaseEdgeData {
  isSelected?: boolean;
  controlOffset?: { x: number; y: number };
  replayHighlight?: string;
  isLocked?: boolean;
  locked?: boolean;
  /** Global canvas lock state (read-only / standalone / user-locked canvas). */
  globalLocked?: boolean;
  edgeOrdersVisible?: boolean;
  edgeOrderInfo?: EdgeOrderInfo;
  onEdgeUpdate?: (id: string, updates: { controlOffset: { x: number; y: number } }) => void;
  onReorderEdge?: (sourceNodeId: string, fromOrder: number, toOrder: number) => void;
}

/**
 * Base data interface shared by all node component types.
 */
export interface BaseNodeData {
  label?: string;
  plugin?: string;
  locked?: boolean;
  annotation?: string;
  isAnnotationVisible?: boolean;
  isLocked?: boolean;
  onDelete?: () => void;
  onToggleAnnotation?: () => void;
  onQuickAdd?: (component: any) => void;
}
