/** Generic values accepted by the Product 3D parametric runtime. */
export type AsukaParametricValue = string | number | boolean | null;

/** A literal value or a safe expression evaluated against parameters/computed values/runtime measurements. */
export type AsukaParametricExpression = AsukaParametricValue;

export type AsukaParametricParameterType = 'number' | 'integer' | 'boolean' | 'select';

export interface AsukaParametricSelectOption {
  value: string | number | boolean;
  label: string;
  disabledWhen?: AsukaParametricExpression;
}

export type AsukaParametricLengthDimension = 'width' | 'height' | 'depth';

export type AsukaParametricLengthStorage = 'percent' | 'world-unit' | 'physical';

/**
 * Describes how a numeric parameter maps to a real length.
 *
 * Recipes may keep their established storage format (for example `100` for
 * 100 percent) while every editor presents the value in the view's selected
 * production unit.
 */
export interface AsukaParametricParameterMeasurement {
  kind: 'length';
  dimension: AsukaParametricLengthDimension;
  /** Semantic part id. Omit it to use the complete product bounds. */
  target?: string;
  /** Defaults to `world-unit`, unless the legacy parameter unit is `%`. */
  storage?: AsukaParametricLengthStorage;
  /** Source unit when `storage` is `physical`. */
  unit?: 'm' | 'cm' | 'mm' | 'in';
}

export interface AsukaParametricParameter {
  id: string;
  label?: string;
  description?: string;
  type: AsukaParametricParameterType;
  unit?: string;
  measurement?: AsukaParametricParameterMeasurement;
  default?: AsukaParametricValue;
  min?: number | AsukaParametricExpression;
  max?: number | AsukaParametricExpression;
  step?: number;
  options?: AsukaParametricSelectOption[];
  visibleWhen?: AsukaParametricExpression;
  enabledWhen?: AsukaParametricExpression;
  metadata?: Record<string, unknown>;
}

export interface AsukaParametricParameterGroup {
  id: string;
  label?: string;
  description?: string;
  icon?: string;
  parameters: string[];
  visibleWhen?: AsukaParametricExpression;
}

/** A free semantic role defined by each product (body, sole, frame.right, handle...). */
export interface AsukaParametricPartDefinition {
  selectors: string[];
  includeDescendants?: boolean;
  metadata?: Record<string, unknown>;
}

export interface AsukaParametricVectorExpression {
  x?: AsukaParametricExpression;
  y?: AsukaParametricExpression;
  z?: AsukaParametricExpression;
}

export interface AsukaParametricRuleBase {
  id?: string;
  target: string;
  when?: AsukaParametricExpression;
  metadata?: Record<string, unknown>;
}

/**
 * Apply offsets/rotations/scales relative to the original imported transform.
 * Rotation expressions are expressed in degrees. Scale expressions are multipliers.
 */
export interface AsukaParametricTransformRule extends AsukaParametricRuleBase {
  type: 'transform';
  positionOffset?: AsukaParametricVectorExpression;
  rotationOffset?: AsukaParametricVectorExpression;
  scale?: AsukaParametricVectorExpression;
}

/** Resize a semantic part to requested world dimensions without accumulating transforms. */
export interface AsukaParametricResizeRule extends AsukaParametricRuleBase {
  type: 'resize';
  size: AsukaParametricVectorExpression;
}

/**
 * Keep one semantic part attached to another while either part is resized.
 *
 * Anchor coordinates are normalized inside each measured part:
 * `-0.5` is the minimum face, `0` the center and `0.5` the maximum face.
 * The keywords `min`, `center`, `max` and `auto` are also accepted. `auto`
 * infers the original contact/relative position from the imported model.
 */
export interface AsukaParametricAttachRule extends AsukaParametricRuleBase {
  type: 'attach';
  /** Semantic support part that the target follows. */
  to: string;
  /** Attachment point on the support. Defaults to `auto` on every axis. */
  supportAnchor?: AsukaParametricVectorExpression;
  /** Attachment point on the target. Defaults to `auto` on every axis. */
  targetAnchor?: AsukaParametricVectorExpression;
  /** Optional final offset in world units, useful for user-controlled spacing. */
  positionOffset?: AsukaParametricVectorExpression;
}

/** Enable/disable a semantic part. */
export interface AsukaParametricVisibilityRule extends AsukaParametricRuleBase {
  type: 'visibility';
  visible: AsukaParametricExpression;
}

export type AsukaParametricRule =
  | AsukaParametricTransformRule
  | AsukaParametricResizeRule
  | AsukaParametricAttachRule
  | AsukaParametricVisibilityRule;

export interface AsukaParametricConstraint {
  id?: string;
  expression: AsukaParametricExpression;
  message: string;
  severity?: 'error' | 'warning';
  parameters?: string[];
}


export type AsukaParametricVariationPlacement = 'before' | 'after';

/** Reserved scope used when the Variations browser is at the product root. */
export const ASUKA_PARAMETRIC_VARIATION_PRODUCT_SCOPE = '@product';

/** One contextual parameter set shown for the product root or a concrete Product 3D part. */
export interface AsukaParametricVariationScope {
  /** `@product` or a Product 3D part id/label such as `body`, `sole`, `front-panel`... */
  target: string;
  /** Ordered parameter ids exposed only while this target is the active Variations context. */
  parameterIds: string[];
  /** Optional target-specific heading. */
  title?: string;
  /** Optional target-specific helper text. */
  description?: string;
}

/** Controls how one product exposes its generic parameters inside the Variations module. */

/** Parameters exposed directly from one product/part variation node. */
export interface AsukaElementVariationParametricControls {
  /** Local opt-out. The global Product 3D Variations setting must still be enabled. */
  enabled?: boolean;
  /** Ordered ids from the owning element parametric recipe. */
  parameterIds?: string[];
  /** Optional heading overriding the product-level default for this variation node. */
  title?: string;
  /** Optional helper text overriding the product-level default for this variation node. */
  description?: string;
}

export interface AsukaParametricVariationControls {
  /** Opt-in flag. Parametric products remain hidden from Variations unless explicitly enabled. */
  enabled?: boolean;
  /** Position relative to the current variation list. */
  placement?: AsukaParametricVariationPlacement;
  /** Optional custom heading shown to the end user. */
  title?: string;
  /** Optional helper text shown below the heading. */
  description?: string;
  /** Contextual parameter sets. No matching scope means no dimension controls are rendered. */
  scopes?: AsukaParametricVariationScope[];
  /** Keep the controls visually compact inside contextual variation panels. */
  compact?: boolean;
}

export interface AsukaParametricUiDefinition {
  variationControls?: AsukaParametricVariationControls;
}

export interface AsukaParametricDefinition {
  schemaVersion: 1;
  parameters: AsukaParametricParameter[];
  groups?: AsukaParametricParameterGroup[];
  parts: Record<string, AsukaParametricPartDefinition>;
  computedValues?: Record<string, AsukaParametricExpression>;
  rules: AsukaParametricRule[];
  constraints?: AsukaParametricConstraint[];
  /** Optional presentation settings. Runtime geometry stays independent from the UI. */
  ui?: AsukaParametricUiDefinition;
  metadata?: Record<string, unknown>;
}

export interface AsukaParametricState {
  values: Record<string, AsukaParametricValue>;
}

export interface AsukaParametricIssue {
  id?: string;
  severity: 'error' | 'warning';
  message: string;
  parameters?: string[];
}

export interface AsukaParametricEvaluation {
  values: Record<string, AsukaParametricValue>;
  computedValues: Record<string, AsukaParametricValue>;
  context: Record<string, unknown>;
  issues: AsukaParametricIssue[];
  valid: boolean;
}

export interface AsukaParametricRuntimePartMeasurement {
  width: number;
  height: number;
  depth: number;
  centerX?: number;
  centerY?: number;
  centerZ?: number;
}

export interface AsukaParametricRuntimeMeasurements {
  product?: AsukaParametricRuntimePartMeasurement;
  parts?: Record<string, AsukaParametricRuntimePartMeasurement>;
}

export interface AsukaParametricProductDescriptor {
  productId: string;
  catalogId?: string;
  name?: string;
  definition: AsukaParametricDefinition;
  state: AsukaParametricState;
  evaluation: AsukaParametricEvaluation;
}

export interface AsukaParametricMutationOptions {
  source?: string;
  commitHistory?: boolean;
  emitChange?: boolean;
  validate?: boolean;
}
