/**
 * Types for athanor-embed.js: the Athanor structure editor in an iframe,
 * protocol "athanor-embed" version 1. See docs/EMBED.md.
 */

export type ToolId = 'select' | 'bond' | 'ring' | 'charge' | 'text' | 'erase' | 'arrow' | 'shape' | 'annotate' | 'orbital';

export interface EmbedOptions {
  /** The Athanor app's address. Defaults to the site this script was loaded from. */
  src?: string;
  /** A structure to open with, as SMILES. */
  smiles?: string;
  /** A structure to open with, as a molfile (V2000 or V3000). Wins over `smiles`. */
  molfile?: string;
  /** The tools on the slim toolbar, in order. Default: select, bond, ring, charge, text, erase. [] for none. */
  tools?: ToolId[];
  /** Open view only: no editing, no toolbar; the wheel still zooms. */
  readOnly?: boolean;
  /** Default: the reader's own preference. */
  theme?: 'dark' | 'light';
  /** What a screen reader calls the editor. Default "Structure editor". */
  label?: string;
  /** Show R/S and E/Z labels on stereocenters. Default false, as in the app. */
  stereo?: boolean;
  /** The iframe's CSS height. Default "100%" of the container. */
  height?: string;
  /** How long to wait for the editor to answer, in ms. Default 20000. */
  timeout?: number;
}

export interface ChangeEvent {
  protocol: 'athanor-embed';
  v: 1;
  event: 'change';
  /** The structure as SMILES, after the change. */
  smiles: string;
  /** How many atoms are on the page. */
  atoms: number;
}

export interface ReadyEvent {
  protocol: 'athanor-embed';
  v: 1;
  event: 'ready';
  version: number;
  smiles: string;
}

export interface AthanorEditorHandle {
  readonly iframe: HTMLIFrameElement;
  readonly version: 1;
  /** Whether it opened view only. */
  readOnly: boolean;
  getSmiles(): Promise<string>;
  getMolfile(): Promise<string>;
  /** Any of smiles, molfile, molV3000, sdf, mrv, cml, cdxml, cdx (base64), inchi, inchikey, xyz, mol2, pdb (protocol 1). */
  getStructure(format: "smiles" | "molfile" | "molV3000" | "sdf" | "mrv" | "cml" | "cdxml" | "cdx" | "inchi" | "inchikey" | "xyz" | "mol2" | "pdb"): Promise<string>;
  /** The page as an SVG document, at its own size, on no background. */
  getSvg(): Promise<string>;
  /** The page as a PNG data URL; `scale` 0.25 to 8, default 2. */
  getPng(scale?: number): Promise<string>;
  /** The engine's own systematic name (what Athanor's Compound info shows); rejects with the reason when it gives none. */
  getName(): Promise<string>;
  /** Formula, molar mass (g/mol), exact mass and net charge of what is drawn. */
  getFormula(): Promise<FormulaResult>;
  /** Replace the page with this structure. Resolves to its SMILES; rejects with the reason it could not be read. */
  setStructure(data: string | ArrayBuffer | Uint8Array, format?: 'smiles' | 'molfile' | 'mrv' | 'cdxml' | 'cdx' | 'sdf' | 'cml' | 'xyz' | 'mol2' | 'rxn' | 'inchi' | 'helm' | 'auto'): Promise<string>;
  /** Draw a DNA, RNA or peptide from its letters; resolves with its SMILES. Since 1.1. */
  buildSequence(kind: 'dna' | 'rna' | 'peptide', sequence: string, opts?: { double?: boolean }): Promise<string>;
  /** A sequence operation, answered without touching the page. Strands 5' to 3', proteins one-letter. Since 1.1. */
  sequence(op: 'transcribe-template' | 'transcribe-coding' | 'replicate' | 'translate' | 'back-translate', sequence: string): Promise<{ kind: 'dna' | 'rna' | 'peptide'; sequence: string }>;
  clear(): Promise<true>;
  setReadOnly(readOnly: boolean): Promise<boolean>;
  /** Listen for `change` (debounced, 300 ms) or `ready`. Returns the way to stop listening. */
  on(event: 'change', cb: (e: ChangeEvent) => void): () => void;
  on(event: 'ready', cb: (e: ReadyEvent) => void): () => void;
  destroy(): void;
}

export interface FormulaResult {
  formula: string;
  weight: number | null;
  exactMass: number | null;
  charge: number;
}

export interface AthanorEmbedApi {
  /** Create an editor in `container` (an element or a selector); resolves once it has answered the handshake. */
  create(container: Element | string, options?: EmbedOptions): Promise<AthanorEditorHandle>;
  /** The iframe address `create` would use. */
  embedUrl(options?: EmbedOptions): URL;
  readonly PROTOCOL: 'athanor-embed';
  readonly VERSION: 1;
}

/** `<athanor-editor smiles tools readonly theme src label>`: the same editor as an element. */
export interface AthanorEditorElement extends HTMLElement {
  readonly ready: Promise<AthanorEditorHandle>;
  readonly editor: AthanorEditorHandle | null;
  getSmiles(): Promise<string>;
  getMolfile(): Promise<string>;
  /** Any of smiles, molfile, molV3000, sdf, mrv, cml, cdxml, cdx (base64), inchi, inchikey, xyz, mol2, pdb (protocol 1). */
  getStructure(format: "smiles" | "molfile" | "molV3000" | "sdf" | "mrv" | "cml" | "cdxml" | "cdx" | "inchi" | "inchikey" | "xyz" | "mol2" | "pdb"): Promise<string>;
  getSvg(): Promise<string>;
  getPng(scale?: number): Promise<string>;
  getName(): Promise<string>;
  getFormula(): Promise<FormulaResult>;
  setStructure(data: string | ArrayBuffer | Uint8Array, format?: 'smiles' | 'molfile' | 'mrv' | 'cdxml' | 'cdx' | 'sdf' | 'cml' | 'xyz' | 'mol2' | 'rxn' | 'inchi' | 'helm' | 'auto'): Promise<string>;
  /** Draw a DNA, RNA or peptide from its letters; resolves with its SMILES. Since 1.1. */
  buildSequence(kind: 'dna' | 'rna' | 'peptide', sequence: string, opts?: { double?: boolean }): Promise<string>;
  /** A sequence operation, answered without touching the page. Strands 5' to 3', proteins one-letter. Since 1.1. */
  sequence(op: 'transcribe-template' | 'transcribe-coding' | 'replicate' | 'translate' | 'back-translate', sequence: string): Promise<{ kind: 'dna' | 'rna' | 'peptide'; sequence: string }>;
  clear(): Promise<true>;
  setReadOnly(readOnly: boolean): Promise<boolean>;
  addEventListener(type: 'change', listener: (e: CustomEvent<ChangeEvent>) => void): void;
  addEventListener(type: 'ready', listener: (e: CustomEvent<{ version: number }>) => void): void;
  addEventListener(type: string, listener: EventListenerOrEventListenerObject): void;
}

declare global {
  interface Window { AthanorEmbed: AthanorEmbedApi }
  interface HTMLElementTagNameMap { 'athanor-editor': AthanorEditorElement }
}

declare const AthanorEmbed: AthanorEmbedApi;
export default AthanorEmbed;
