import { Assembly, File, Model } from "@inweb/client";
import { IViewpoint } from "./IViewpoint";

/**
 * Event that fires when model loading has been canceled.
 *
 * @event
 */
export interface CancelEvent {
  /**
   * Event type.
   */
  type: "cancel";
}

/**
 * Event that fires when the active dragger has been changed.
 *
 * @event
 */
export interface ChangeActiveDraggerEvent {
  /**
   * Event type.
   */
  type: "changeactivedragger";

  /**
   * Dragger name.
   */
  data: string;
}

/**
 * Event that fires when the default color of new markup objects has been changed.
 *
 * @event
 */
export interface ChangeMarkupColorEvent {
  /**
   * Event type.
   */
  type: "changemarkupcolor";

  /**
   * New color.
   */
  data: { r: number; g: number; b: number };
}

/**
 * Event that fires when the viewer has been cleared.
 *
 * @event
 */
export interface ClearEvent {
  /**
   * Event type.
   */
  type: "clear";
}

/**
 * Event that fires after viewer executes the command.
 *
 * @event
 */
export interface CommandEvent {
  /**
   * Event type.
   */
  type: "command";

  /**
   * Command name.
   */
  data: string;

  /**
   * Command arguments.
   */
  args: any[];
}

/**
 * Event that fires when the model scene description file has been loaded.
 *
 * @event
 */
export interface DatabaseChunkEvent {
  /**
   * Event type.
   */
  type: "databasechunk";

  /**
   * Scene description file.
   */
  data?: Uint8Array;

  /**
   * Model instance to open.
   */
  model?: Model;

  /**
   * Buffer to open.
   */
  buffer?: Uint8Array | ArrayBuffer;
}

/**
 * Event that fires before viewer resources has been released.
 *
 * @event
 */
export interface DisposeEvent {
  /**
   * Event type.
   */
  type: "dispose";
}

/**
 * Event that fires when model breaks into its component objects or collect objects back.
 *
 * @event
 */
export interface ExplodeEvent {
  /**
   * Event type.
   */
  type: "explode";

  /**
   * Explode index. Range is 0 to 100.
   */
  data: number;
}

/**
 * Event that fires when the model geometry data chunk has been loaded.
 *
 * Note that small files are loaded in one chunk, and `geometrychunk` event does not fire, only the
 * `databasechink` event fires.
 *
 * @event
 */
export interface GeometryChunkEvent {
  /**
   * Event type.
   */
  type: "geometrychunk";

  /**
   * Geometry data chunk.
   */
  data: Uint8Array;

  /**
   * Model instance to open.
   */
  model?: Model;

  /**
   * Buffer to open.
   */
  buffer?: Uint8Array | ArrayBuffer;
}

/**
 * Event that fires after model has been successfully loaded.
 *
 * @event
 */
export interface GeometryEndEvent {
  /**
   * Event type.
   */
  type: "geometryend";

  /**
   * Model instance to open.
   */
  model?: Model;

  /**
   * Buffer to open.
   */
  buffer?: Uint8Array | ArrayBuffer;

  /**
   * Loaded data (viewer depended).
   */
  data?: any;
}

/**
 * Event that fires when the model fails to load.
 *
 * @event
 */
export interface GeometryErrorEvent {
  /**
   * Event type.
   */
  type: "geometryerror";

  /**
   * Thrown exception.
   */
  data: Error;

  /**
   * Model instance to open.
   */
  model?: Model;

  /**
   * Buffer to open.
   */
  buffer?: Uint8Array | ArrayBuffer;
}

/**
 * Event that measures the progress of the model loading.
 *
 * @event
 */
export interface GeometryProgressEvent {
  /**
   * Event type.
   */
  type: "geometryprogress";

  /**
   * The non-rounded progress value from 0 to 1. To get a percentage (%), multiply the `data` by 100.
   */
  data: number;

  /**
   * Model instance to open.
   */
  model?: Model;

  /**
   * Buffer to open.
   */
  buffer?: Uint8Array | ArrayBuffer;
}

/**
 * Event that fires before the model loads.
 *
 * @event
 */
export interface GeometryStartEvent {
  /**
   * Event type.
   */
  type: "geometrystart";

  /**
   * Model instance to open.
   */
  model?: Model;

  /**
   * Buffer to open.
   */
  buffer?: Uint8Array | ArrayBuffer;
}

/**
 * Event that fires after selected objects becomes invisible.
 *
 * @event
 */
export interface HideEvent {
  /**
   * Event type.
   */
  type: "hide";
}

/**
 * Event that fires after the viewer initialized.
 *
 * @event
 */
export interface InitializeEvent {
  /**
   * Event type.
   */
  type: "initialize";
}

/**
 * Event that measures the progress of the viewer's initialization.
 *
 * @event
 */
export interface InitializeProgressEvent {
  /**
   * Event type.
   */
  type: "initializeprogress";

  /**
   * The non-rounded progress value from 0 to 1. To get a percentage (%), multiply the `data` by 100.
   */
  data: number;

  /**
   * A 64-bit unsigned integer value indicating the amount of work already performed by the underlying
   * process. The ratio of work done can be calculated by dividing total by the value of this property.
   */
  loaded: number;

  /**
   * A 64-bit unsigned integer representing the total amount of work that the underlying process is in
   * the progress of performing.
   */
  total: number;
}

/**
 * Event that fires after selected objects becomes isolated.
 *
 * @event
 */
export interface IsolateEvent {
  /**
   * Event type.
   */
  type: "isolate";
}

/**
 * Event that fires before model opens.
 *
 * @event
 */
export interface OpenEvent {
  /**
   * Event type.
   */
  type: "open";

  /**
   * File instance to open. Only defined when loading a file from the server.
   */
  file?: File | Assembly | Model;

  /**
   * Deprecated since `25.3`. Use `file` instead.
   *
   * @deprecated
   */
  model?: File | Assembly | Model;

  /**
   * Buffer to open. Only defined when loading a local file.
   */
  buffer?: Uint8Array | ArrayBuffer;
}

/**
 * Event that fires when rendering occurs.
 *
 * @event
 */
export interface RenderEvent {
  /**
   * Event type.
   */
  type: "render";

  /**
   * Render time.
   */
  time: DOMHighResTimeStamp;

  /**
   * The milliseconds passed since the previous render.
   */
  deltaTime: DOMHighResTimeStamp;
}

/**
 * Event that fires when resize occurs.
 *
 * @event
 */
export interface ResizeEvent {
  /**
   * Event type.
   */
  type: "resize";

  /**
   * New width.
   */
  width: number;

  /**
   * New height.
   */
  height: number;
}

/**
 * Event that fires when the selection changes.
 *
 * @event
 */
export interface SelectEvent {
  /**
   * Event type.
   */
  type: "select";

  /**
   * Selection set (viewer dependent).
   */
  data: any;

  /**
   * Handles of selected entities.
   */
  handles: string[];
}

/**
 * Event that fires after all objects becomes visible.
 *
 * @event
 */
export interface ShowAllEvent {
  /**
   * Event type.
   */
  type: "showall";
}

/**
 * Event that fires when an update occurs.
 *
 * @event
 */
export interface UpdateEvent {
  /**
   * Event type.
   */
  type: "update";

  /**
   * `true` to force the update, otherwise the update is delayed until the next animation frame.
   */
  data: boolean;
}

/**
 * Deprecated since `25.4`. Use `initializeprogress` instead.
 *
 * @deprecated
 * @event
 */
export interface VisualizeProgressEvent {
  /**
   * Event type.
   */
  type: "visualizeprogress";

  /**
   * A 64-bit unsigned integer value indicating the amount of work already performed by the underlying
   * process. The ratio of work done can be calculated by dividing total by the value of this property.
   */
  loaded: number;

  /**
   * A 64-bit unsigned integer representing the total amount of work that the underlying process is in
   * the progress of performing.
   */
  total: number;
}

/**
 * Event that fires after viewer loads a viewpoint.
 *
 * @event
 */
export interface ViewpointEvent {
  /**
   * Event type.
   */
  type: "drawviewpoint" | "createviewpoint";

  /**
   * Viewpoint.
   */
  data: IViewpoint;
}

/**
 * Event that fires when walk speed changing.
 *
 * @event
 */
export interface WalkSpeedChangeEvent {
  /**
   * Event type.
   */
  type: "walkspeedchange";

  /**
   * Walk speed multiplier.
   */
  data: number;
}

/**
 * Event that fires when walk started.
 *
 * @event
 */
export interface WalkStartEvent {
  /**
   * Event type.
   */
  type: "walkstart";
}

/**
 * Event that fires when camera panning.
 *
 * @event
 */
export interface PanEvent {
  /**
   * Event type.
   */
  type: "pan";

  /**
   * The X coordinate of the mouse pointer in screen coordinates.
   */
  x: number;

  /**
   * The Y coordinate of the mouse pointer in screen coordinates.
   */
  y: number;

  /**
   * The X coordinate delta of the mouse pointer relative to the position of the last `Pan` event.
   */
  dX: number;

  /**
   * The Y coordinate delta of the mouse pointer relative to the position of the last `Pan` event.
   */
  dY: number;
}

/**
 * Event that fires when zooming to extents or selected objects.
 *
 * @event
 */
export interface ZoomEvent {
  /**
   * Event type.
   */
  type: "zoom";

  /**
   * New view parameters.
   */
  data?: any;
}

/**
 * Event that fires when zooming of the camera using mouse wheel.
 *
 * @event
 */
export interface ZoomAtEvent {
  /**
   * Event type.
   */
  type: "zoomat";

  /**
   * New zoom factor.
   */
  data: number;

  /**
   * X coordinate of the mouse pointer in screen coordinates.
   */
  x: number;

  /**
   * Y coordinate of the mouse pointer in screen coordinates.
   */
  y: number;
}

/**
 * Event that fires when zooming to object.
 *
 * @event
 */
export interface ZoomToEntityEvent {
  /**
   * Event type.
   */
  type: "zoomtoentity";

  /**
   * Object to zoom.
   */
  data: any;
}

/**
 * Viewer Events.
 *
 * @event
 */
export interface ViewerEventMap {
  /**
   * Event that fires when model loading has been canceled.
   */
  cancel: CancelEvent;

  /**
   * Event that fires when the active dragger has been changed.
   */
  changeactivedragger: ChangeActiveDraggerEvent;

  /**
   * Event that fires when the markup color has been changed.
   */
  changemarkupcolor: ChangeMarkupColorEvent;

  /**
   * Event that fires when the viewer has been cleared.
   */
  clear: ClearEvent;

  /**
   * Event that fires after viewer executes the command.
   */
  command: CommandEvent;

  /**
   * Event that fires after viewer creates a viewpoint.
   */
  createviewpoint: ViewpointEvent;

  /**
   * Event that fires when the model scene description file has been loaded.
   */
  databasechunk: DatabaseChunkEvent;

  /**
   * Event that fires before viewer resources has been released.
   */
  dispose: DisposeEvent;

  /**
   * Event that fires after viewer loads a viewpoint.
   */
  drawviewpoint: ViewpointEvent;

  /**
   * Event that fires when model breaks into its component objects or collect objects back.
   */
  explode: ExplodeEvent;

  /**
   * Event that fires when the model geometry data chunk has been loaded.
   */
  geometrychunk: GeometryChunkEvent;

  /**
   * Event that fires after model has been successfully loaded.
   */
  geometryend: GeometryEndEvent;

  /**
   * Event that fires when the model fails to open.
   */
  geometryerror: GeometryErrorEvent;

  /**
   * Event that measures the progress of the model loading.
   */
  geometryprogress: GeometryProgressEvent;

  /**
   * Event that fires before the model opens.
   */
  geometrystart: GeometryStartEvent;

  /**
   * Event that fires after selected objects becomes invisible.
   */
  hide: HideEvent;

  /**
   * Event that fires after the viewer initialized.
   */
  initialize: InitializeEvent;

  /**
   * Event that measures the progress of the viewer's initialization.
   */
  initializeprogress: InitializeProgressEvent;

  /**
   * Event that fires after selected objects becomes isolated.
   */
  isolate: IsolateEvent;

  /**
   * Event that fires before model opens.
   */
  open: OpenEvent;

  /**
   * Event that fires when camera panning.
   */
  pan: PanEvent;

  /**
   * Event that fires when an rendering occurs.
   */
  render: RenderEvent;

  /**
   * Event that fires when resize occurs.
   */
  resize: ResizeEvent;

  /**
   * Event that fires when the selection changes.
   */
  select: SelectEvent;

  /**
   * Event that fires after all objects becomes visible.
   */
  showall: ShowAllEvent;

  /**
   * Event that fires when an update occurs.
   */
  update: UpdateEvent;

  /**
   * Deprecated since `25.4`. Use `initializeprogress` instead.
   *
   * @deprecated
   */
  visualizeprogress: VisualizeProgressEvent;

  /**
   * Event that fires when walk speed changing.
   */
  walkspeedchange: WalkSpeedChangeEvent;

  /**
   * Event that fires when walk started.
   */
  walkstart: WalkStartEvent;

  /**
   * Event that fires when zooming to extents or selected objects.
   */
  zoom: ZoomEvent;

  /**
   * Event that fires when zooming of the camera using mouse wheel.
   */
  zoomat: ZoomAtEvent;

  /**
   * Event that fires when zooming to object.
   */
  zoomtoentity: ZoomToEntityEvent;
}
