/**
 * The shape of a WAZO3D plugin, for editors that read TypeScript declarations (a plugin itself is
 * plain JavaScript). The full description is in README.md beside this file.
 */

/** Words in one language, or in WAZO3D's three. */
export type Texts = string | { en?: string; nl?: string; de?: string };

interface ParamBase {
  id: string;
  label: Texts;
  /** Shown when the pointer rests on the setting. */
  hint?: Texts;
  /** The id of the section it stands in; without one it stands above every section. */
  section?: string;
  /** Shown only while every named setting holds that value (or one of a list of values). Its value is kept meanwhile. */
  when?: Record<string, string | number | boolean | (string | number | boolean)[]>;
  /** For a host that builds the plugin by name only: never shown in WAZO3D's dialog, its default used there. */
  host?: boolean;
}

/** One setting the plugin asks for. A number with `unit: 'mm'` is shown and typed in the user's own unit. */
export type Param =
  | ParamBase & { type: 'number'; default: number; min?: number; max?: number; step?: number; unit?: 'mm' | 'deg' | ''; integer?: boolean; /** a slider beside the field; needs min and max */ slider?: boolean }
  | ParamBase & { type: 'choice'; default: string; options: { value: string; label: Texts }[] }
  | ParamBase & { type: 'boolean'; default: boolean }
  | ParamBase & { type: 'text'; default: string; /** at most 2000, 100 by default */ maxLength?: number; multiline?: boolean }
  | ParamBase & { type: 'font'; default: FontId }
  /** A file of the user's own, kept in their browser; its value is the file's id, or '' for none. */
  | ParamBase & { type: 'file'; /** none chosen to begin with */ default?: ''; /** the extensions it takes, such as ['csv', 'txt'] */ accept: string[] };

/**
 * WAZO3D's fonts: Barlow (Bold), Roboto Slab (Bold), JetBrains Mono, Allerta Stencil, Patrick Hand, Oswald (Bold),
 * Bebas Neue, Nunito (Bold), Pacifico, UnifrakturMaguntia, Special Elite, Poiret One. A font setting may also hold a
 * font of the user's own, `file:` and a hash.
 */
export type FontId = 'sans' | 'sans-bold' | 'serif' | 'serif-bold' | 'mono' | 'stencil' | 'hand' | 'condensed' | 'condensed-bold'
  | 'display' | 'rounded' | 'rounded-bold' | 'script' | 'gothic' | 'typewriter' | 'deco' | `file:${string}`;

/** A file of the user's own a `file` setting chose. */
export interface File {
  name: string;
  /** Its extension, in small letters. */
  ext: string;
  size: number;
  bytes: Uint8Array;
  /** For a text file that reads as UTF-8. */
  text?: string;
}

/** A glyph's shapes, in ems, y up, the baseline at nought. */
export interface Glyph { advance: number; shapes: { outline: Point[]; holes: Point[][] }[] }

/** A font as a plugin is handed it: the characters its texts hold, in ems (1 em = the font's size). */
export interface Font {
  id: FontId;
  ascender: number;
  descender: number;
  /** How tall a capital letter stands. */
  capHeight: number;
  glyphs: Record<string, Glyph>;
  /** By the pair of characters: how much closer (negative) or further they stand. */
  kerning: Record<string, number>;
  /** Characters the font has no glyph for. */
  missing: string[];
}

/** What WAZO3D hands `build` besides the values. */
export interface Wazo {
  /** The fonts the plugin's `font` settings chose, by font id, holding every character of its `text` settings. */
  fonts: Partial<Record<FontId, Font>>;
  /** The files the plugin's `file` settings chose, by the setting's id; a setting with none is not there. */
  files: Partial<Record<string, File>>;
  /** The language the user reads WAZO3D in ('en', 'nl', 'de', 'es'), for words a plugin writes into its model. */
  language: string;
  /** Who is signed in to WAZO3D, when somebody is: for a name a plugin puts into what it makes (24 Oct 2026). */
  user?: { name: string };
}

/** A heading settings are grouped under; folded shut unless `open`. */
export interface Section { id: string; label: Texts; hint?: Texts; open?: boolean }

/** A named set of values; choosing it fills in the settings it names. */
/** A named set of values; `when` offers it only while those settings hold (a scale's own presets, shown after the scale). */
export interface Preset { id: string; label: Texts; values: Record<string, number | string | boolean>; when?: Record<string, number | string | boolean | (number | string | boolean)[]> }

/** A figure `build` worked out, shown under the settings. */
export interface Figure { label: Texts; value: number | string; unit?: 'mm' | 'deg' | '' }

/** A point (x, y) of an outline in the plane z = 0, or (r, z) of a profile to revolve; millimetres. */
export type Point = [number, number];

/** What a plugin hands back: WAZO3D builds these, in order, into one closed solid. */
export type Step =
  | { op: 'extrude'; outline: Point[]; depth: number; holes?: Point[][]; z?: number; part?: string }
  | { op: 'revolve'; profile: Point[]; segments?: number; part?: string }
  | { op: 'cut'; outline: Point[]; depth?: number; /** stop this far in front of z = 0 instead of past everything */ front?: number; part?: string }
  | { op: 'collar'; outline: Point[]; width: number; depth: number }
  | { op: 'coping'; height: number; overhang?: number; y?: number }
  | { op: 'group'; steps: Step[]; at?: [number, number, number]; turn?: number; tilt?: number; roll?: number }
  | { op: 'repeat'; steps: Step[]; count: number; every: [number, number, number] }
  /** After every other step: the closed piece nearest `pick` rolled (about x, +90 takes y to z), tilted (about z), turned (about y) and moved by `at`; only at the top. */
  | { op: 'move'; pick: [number, number, number]; at?: [number, number, number]; tilt?: number; turn?: number; roll?: number }
  /** Every closed piece laid out on the ground beside the others, after the moves: along x or turned a quarter, in rows no longer than `width` mm, `gap` apart, taking the least area. Only at the top. */
  | { op: 'arrange'; gap?: number; width?: number }
  | { op: 'paint'; part: string; colour: string }
  | { op: 'paint'; part: string; texture: { series: 'realistic' | 'stylized' | 'retro'; id: string } };

/** What `build` hands back. */
/** What `build` hands back: the steps, or why it cannot make what was asked (`refused`, in the user's language). */
/**
 * A grid what is made clicks on once placed: a tile of a modular system. Square tiles have a corner of
 * their cells on the origin, hex tiles the middle of a cell (flats facing ±x); the grid lies in x–z, y up.
 */
export interface Grid {
  /** Tiles of one system click together. */
  system: string;
  shape?: 'square' | 'hex';
  /** A square cell's side, or a hex cell's width across its flats, in millimetres. */
  cell: number;
  /** How high one level is, in millimetres; left out, every tile stays on its neighbour's level. */
  rise?: number;
}

/**
 * A point of what is made that another system hangs something on: where a mast holds the contact wire (`contact`) or
 * the messenger (`messenger`), where a tension mast pulls (`pull`). In the model's millimetres; `cantilever` counts
 * from 0 (a portal's track); `toward` a direction (for `pull`, the way the wire runs off). The .glb carries each as an
 * empty node `wazo:anchor:<kind>:<cantilever>` with `extras.wazo`. At most 64, kinds a short word in small letters.
 */
export interface Anchor {
  kind: string;
  cantilever?: number;
  at: [number, number, number];
  toward?: [number, number, number];
  /** Plain data a host is told about it (a lamp's colour, an arm's positions), at most 1000 characters as JSON. */
  extras?: Record<string, unknown>;
}

/** The values a choice setting may take for what was made, of its own options: the dialog offers only those, and hides the setting with one or none. */
export type Offers = Record<string, string[]>;

export type Result = Step[] | { steps: Step[]; figures?: Figure[]; notes?: Texts[]; grid?: Grid; anchors?: Anchor[]; name?: Texts; offers?: Offers } | { refused: Texts };

/** The icons a plugin may put on its ribbon button. */
export type PluginIcon = 'code' | 'cog' | 'wheel' | 'letters' | 'train' | 'box' | 'star' | 'sparkles' | 'shapes' | 'wrench' | 'ruler'
  | 'house' | 'tree' | 'flower' | 'heart' | 'bolt' | 'puzzle' | 'hexagon' | 'gem' | 'lamp' | 'fence' | 'chair' | 'car' | 'rocket'
  | 'anchor' | 'calculator';

export interface WazoPlugin {
  /** Small letters, digits, dots and dashes: `yourname.thing`. */
  id: string;
  version: string;
  name: Texts;
  description?: Texts;
  author?: string;
  /** Under what licence others may use it: `MIT`, `CC0-1.0`… Shown on the site when it is published. */
  licence?: string;
  /** The plan it says placing what it makes needs; WAZO3D checks it against what it really makes. */
  plan?: 'free' | 'power';
  /**
   * A button of its own on the ribbon, which opens its dialog: one of WAZO3D's icons by name, or an icon of its own as
   * SVG path data in a 24 × 24 box, drawn stroked (at most 12 paths). The plugin editor's Insert a file makes one from an SVG.
   */
  button?: PluginIcon | { paths: string[] };
  params: Param[];
  sections?: Section[];
  presets?: Preset[];
  /**
   * The steps for these settings, each setting by its id; or the steps with figures and notes to show back.
   * May be async. Throw an Error to say what is wrong.
   */
  build(values: Record<string, number | string | boolean>, wazo: Wazo): Result | Promise<Result>;
}

declare const plugin: WazoPlugin;
export default plugin;
