import { Bounds, Nullable } from 'vtk.js/Sources/types';

import vtkCamera from 'vtk.js/Sources/Rendering/Core/Camera';
import vtkLight from 'vtk.js/Sources/Rendering/Core/Light';
import vtkRenderWindow from 'vtk.js/Sources/Rendering/Core/RenderWindow';
import vtkProp from 'vtk.js/Sources/Rendering/Core/Prop';
import vtkViewport, { IViewportInitialValues } from 'vtk.js/Sources/Rendering/Core/Viewport';
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
import vtkTexture from 'vtk.js/Sources/Rendering/Core/Texture';
import { EventHandler, vtkSubscription } from 'vtk.js/Sources/interfaces';


export interface IRendererInitialValues extends IViewportInitialValues {
	allBounds?: Bounds[];
	ambient?: number[];
	allocatedRenderTime?: number;
	timeFactor?: number;
	automaticLightCreation?: boolean;
	twoSidedLighting?: boolean;
	lastRenderTimeInSeconds?: number;
	lights?: vtkLight[];
	actors?: vtkProp[];
	volumes?: vtkVolume[];
	lightFollowCamera?: boolean;
	numberOfPropsRendered?: number;
	layer?: number;
	preserveColorBuffer?: boolean;
	preserveDepthBuffer?: boolean;
	interactive?: boolean;
	nearClippingPlaneTolerance?: number;
	clippingRangeExpansion?: number;
	erase?: boolean;
	draw?: boolean;
	useShadows?: boolean;
	useDepthPeeling?: boolean;
	occlusionRatio?: number;
	maximumNumberOfPeels?: number;
	texturedBackground?: boolean;
	environmentTexture?: vtkTexture;
	environmentTextureDiffuseStrength?: number;
	environmentTextureSpecularStrength?: number;
	useEnvironmentTextureAsBackground?: boolean;
	pass?: number;
}

export type VtkRendererEvent =
  | { type: 'CreateCameraEvent', camera: vtkCamera }
  | { type: 'ActiveCameraEvent', camera: vtkCamera }
  | { type: 'ComputeVisiblePropBoundsEvent', renderer: vtkRenderer }
  | { type: 'ResetCameraClippingRangeEvent', renderer: vtkRenderer }
  | { type: 'ResetCameraEvent', renderer: vtkRenderer };

export interface vtkRenderer extends vtkViewport {

	/**
	 * 
	 */
	isActiveCameraCreated(): boolean;

	/**
	 * Add different types of props to the renderer.
	 * @param {vtkProp} actor The vtkProp instance.
	 */
	addActor(actor: vtkProp): boolean;

	/**
	 * Check if the renderer already has the specified light.
	 * @param {vtkLight} light The vtkLight instance.
	 */
	hasLight(light: vtkLight): boolean;

	/**
	 * Add a light to the list of lights.
	 * @param {vtkLight} light The vtkLight instance.
	 */
	addLight(light: vtkLight): void;

	/**
	 * Not Implemented yet
	 */
	allocateTime(): any;

	/**
	 * Add a volume to the renderer..
	 * @param volume The vtkVolume instance.
	 */
	addVolume(volume: vtkVolume): boolean;

	/**
	 * Create and add a light to renderer.
	 */
	createLight(): void;

	/**
	 * Compute the bounding box of all the visible props Used in ResetCamera() and ResetCameraClippingRange()
	 */
	computeVisiblePropBounds(): Bounds;

	/**
	 * Get the active camera
	 */
	getActiveCamera(): vtkCamera;

	/**
	 * 
	 */
	getActiveCameraAndResetIfCreated(): vtkCamera;

	/**
	 * Return any actors in this renderer.
	 *   
	 */
	getActors(): vtkProp[];

	/**
	 * Return any actors in this renderer.
	 *   
	 */
	getActorsByReference(): vtkProp[];

	/**
	 * 
	 * @default 100
	 */
	getAllocatedRenderTime(): number;

	/**
	 * 
	 */
	getAutomaticLightCreation(): boolean;

	/**
	 * 
	 * @default null
	 */
	getEnvironmentTexture(): vtkTexture;

	/**
	 * Returns the diffuse strength of the set environment texture.
	 * @default 1
	 */
	getEnvironmentTextureDiffuseStrength(): number;

	/**
	 * Returns the specular strength of the set environment texture.
	 * @default 1
	 */
	getEnvironmentTextureSpecularStrength(): number;

	/**
	  * Gets whether or not the environment texture is being used as the background for the view.
	  * @default false
	  */
	getUseEnvironmentTextureAsBackground(): boolean;

	/**
	 * 
	 * @default null
	 */
	getBackingStore(): any;

	/**
	 * 
	 */
	getClippingRangeExpansion(): number;

	/**
	 * 
	 * @default null
	 */
	getDelegate(): any;

	/**
	 * 
	 * @default true
	 */
	getDraw(): boolean;

	/**
	 * 
	 * @default true
	 */
	getErase(): boolean;

	/**
	 * 
	 * @default true
	 */
	getInteractive(): boolean;

	/**
	 * 
	 * @default -1
	 */
	getLastRenderTimeInSeconds(): number;

	/**
	 * 
	 * @default 0
	 */
	getNumberOfPropsRendered(): number;

	/**
	 * 
	 * @default 
	 */
	getLastRenderingUsedDepthPeeling(): any

	/**
	 * 
	 * @default 0
	 */
	getLayer(): number;

	/**
	 * 
	 * @default true
	 */
	getLightFollowCamera(): boolean;

	/**
	 * 
	 */
	getLights(): vtkLight[];

	/**
	 * 
	 */
	getLightsByReference(): vtkLight[];

	/**
	 * 
	 * @default 4
	 */
	getMaximumNumberOfPeels(): number;

	/**
	 * Return the `Modified Time` which is a monotonic increasing integer
	 * global for all vtkObjects.
	 *
	 * This allow to solve a question such as:
	 *  - Is that object created/modified after another one?
	 *  - Do I need to re-execute this filter, or not? ...
	 *
	 * @return {Number} the global modified time.
	 */
	getMTime(): number;

	/**
	 * 
	 * @default 0
	 */
	getNearClippingPlaneTolerance(): number;

	/**
	 * 
	 * @default 0
	 */
	getOcclusionRatio(): number;

	/**
	 * 
	 * @default null
	 */
	getRenderWindow(): Nullable<vtkRenderWindow>;

	/**
	 * 
	 * @default 0
	 */
	getPass(): number;

	/**
	 * 
	 * @default false
	 */
	getPreserveColorBuffer(): boolean;

	/**
	 * 
	 * @default false
	 */
	getPreserveDepthBuffer(): boolean;

	/**
	 * 
	 * @default null
	 */
	getSelector(): any;

	/**
	 * 
	 * @default 1
	 */
	getTimeFactor(): number;

	/**
	 * 
	 * @default true
	 */
	getTransparent(): boolean;

	/**
	 * 
	 * @default false
	 */
	getTexturedbackground(): boolean;

	/**
	 * 
	 * @default true
	 */
	getTwosidedlighting(): boolean;

	/**
	 * 
	 * @default false
	 */
	getUsedepthpeeling(): boolean;

	/**
	 * 
	 * @default false
	 */
	getUseshadows(): boolean;

	/**
	* 
	*/
	getVTKWindow(): vtkRenderWindow;

	/**
	 * Return the collection of volumes.
	 *  
	 */
	getVolumes(): vtkVolume[];

	/**
	 * Return the collection of volumes.
	 *  
	 */
	getVolumesByReference(): vtkVolume[];

	/**
	 * Create a new Camera suitable for use with this type of Renderer.
	 */
	makeCamera(): vtkCamera;

	/**
	 * Create a new Light suitable for use with this type of Renderer.
	 */
	makeLight(): vtkLight;

	/**
	 * requires the aspect ratio of the viewport as X/Y
	 * @param {Number} x The x coordinate.
	 * @param {Number} y The y coordinate.
	 * @param {Number} z The z coordinate.
	 * @param {Number} aspect 
	 */
	normalizedDisplayToWorld(x: number, y: number, z: number, aspect: number): number[];

	/**
	 * 
	 * @param {Number} x The x coordinate.
	 * @param {Number} y The y coordinate.
	 * @param {Number} z The z coordinate.
	 * @param {Number} aspect 
	 */
	projectionToView(x: number, y: number, z: number, aspect: number): number[];

	/**
	 * Specify the camera to use for this renderer.
	 * @param {vtkCamera} camera The camera object to use.
	 */
	setActiveCamera(camera: vtkCamera): boolean;

	/**
	 * 
	 * @param {Boolean} automaticLightCreation 
	 */
	setAutomaticLightCreation(automaticLightCreation: boolean): boolean;

	/**
	 * 
	 * @param {vtkTexture} environmentTexture 
	 */
	setEnvironmentTexture(environmentTexture: vtkTexture): boolean;

	/**
	 * Sets the diffuse strength of the set environment texture.
	 * @param {number} diffuseStrength the new diffuse strength.
	 */
	setEnvironmentTextureDiffuseStrength(diffuseStrength: number): boolean;

	 /**
	  * Sets the specular strength of the set environment texture.
	  * @param {number} specularStrength the new specular strength.
	  */
	setEnvironmentTextureSpecularStrength(specularStrength: number): boolean;

	/**
	  * Sets whether or not to use the environment texture as the background for the view.
	  * @param {number} textureAsBackground
	  */
	setUseEnvironmentTextureAsBackground(textureAsBackground: boolean): boolean;

	/**
	 * 
	 * @param {*} backingStore 
	 */
	setBackingStore(backingStore: any): boolean;

	/**
	 * 
	 * @param {Number} clippingRangeExpansion 
	 */
	setClippingRangeExpansion(clippingRangeExpansion: number): boolean;

	/**
	 * 
	 * @param delegate 
	 */
	setDelegate(delegate: any): boolean;

	/**
	 * 
	 * @param {Boolean} draw 
	 */
	setDraw(draw: boolean): boolean;

	/**
	 * 
	 * @param {Boolean} erase 
	 */
	setErase(erase: boolean): boolean;

	/**
	 * 
	 * @param {Boolean} interactive 
	 */
	setInteractive(interactive: boolean): boolean;

	/**
	 * 
	 * @param {Number} layer 
	 */
	setLayer(layer: number): void;

	/**
	 * Set the collection of lights.
	 * @param {vtkLight[]} lights 
	 */
	setLightCollection(lights: vtkLight[]): void;

	/**
	 * 
	 * @param {Boolean} lightFollowCamera 
	 */
	setLightFollowCamera(lightFollowCamera: boolean): boolean;

	/**
	 * 
	 * @param {Number} maximumNumberOfPeels 
	 */
	setMaximumNumberOfPeels(maximumNumberOfPeels: number): boolean;

	/**
	 * 
	 * @param {Number} nearClippingPlaneTolerance 
	 */
	setNearClippingPlaneTolerance(nearClippingPlaneTolerance: number): boolean;

	/**
	 * 
	 * @param {Number} occlusionRatio 
	 */
	setOcclusionRatio(occlusionRatio: number): boolean;

	/**
	 * 
	 * @param {Number} pass 
	 */
	setPass(pass: number): boolean;

	/**
	 * 
	 * @param {Boolean} preserveColorBuffer 
	 */
	setPreserveColorBuffer(preserveColorBuffer: boolean): boolean;

	/**
	 * 
	 * @param {Boolean} preserveDepthBuffer 
	 */
	setPreserveDepthBuffer(preserveDepthBuffer: boolean): boolean;

	/**
	 * 
	 * @param {Boolean} texturedBackground 
	 */
	setTexturedBackground(texturedBackground: boolean): boolean;

	/**
	 * 
	 * @param {Boolean} twoSidedLighting 
	 */
	setTwoSidedLighting(twoSidedLighting: boolean): boolean;

	/**
	 * 
	 * @param {Boolean} useDepthPeeling 
	 */
	setUseDepthPeeling(useDepthPeeling: boolean): boolean;

	/**
	 * 
	 * @param {Boolean} useShadows 
	 */
	setUseShadows(useShadows: boolean): boolean;

	/**
	 * Specify the rendering window in which to draw.
	 * @param {vtkRenderWindow} renderWindow 
	 */
	setRenderWindow(renderWindow: vtkRenderWindow): void;

	/**
	 * Remove an actor from the list of actors.
	 * @param {vtkProp} actor 
	 */
	removeActor(actor: vtkProp): void;

	/**
	 * Remove all actors from the list of actors.
	 */
	removeAllActors(): void;

	/**
	 * Remove a volume from the list of volumes.
	 * @param {vtkVolume} volume The volume object to remove.
	 */
	removeVolume(volume: vtkVolume): void;

	/**
	 * Remove all volumes from the list of volumes.
	 */
	removeAllVolumes(): void;

	/**
	 * Remove a light from the list of lights.
	 * @param {vtkLight} light The light object to remove.
	 */
	removeLight(light: vtkLight): void;

	/**
	 * Remove all lights from the list of lights.
	 */
	removeAllLights(): void;

	/**
	 * requires the aspect ratio of the viewport as X/Y
	 * @param {Number} x The x coordinate.
	 * @param {Number} y The y coordinate.
	 * @param {Number} z The z coordinate.
	 * @param {Number} aspect 
	 */
	worldToNormalizedDisplay(x: number, y: number, z: number, aspect: number): number[];

	/**
	 * requires the aspect ratio of the viewport as X/Y
	 * @param {Number} x The x coordinate.
	 * @param {Number} y The y coordinate.
	 * @param {Number} z The z coordinate.
	 */
	viewToWorld(x: number, y: number, z: number): number[];

	/**
	 * Convert world point coordinates to view coordinates.
	 * @param {Number} x The x coordinate.
	 * @param {Number} y The y coordinate.
	 * @param {Number} z The z coordinate.
	 */
	worldToView(x: number, y: number, z: number): number[];

	/**
	 * Convert world point coordinates to view coordinates.
	 * requires the aspect ratio of the viewport as X/Y
	 * @param {Number} x The x coordinate.
	 * @param {Number} y The y coordinate.
	 * @param {Number} z The z coordinate.
	 * @param {Number} aspect 
	 */
	viewToProjection(x: number, y: number, z: number, aspect: number): number[];

	/**
	 * Automatically set up the camera based on the visible actors.
	 * 
	 * The camera will reposition itself to view the center point of the actors,
	 * and move along its initial view plane normal (i.e., vector defined from
	 * camera position to focal point) so that all of the actors can be seen.
	 * @param {Bounds} [bounds] 
	 */
	resetCamera(bounds?: Bounds): boolean;

	/**
	 * Reset the camera clipping range based on a bounding box.
	 * @param {Bounds} [bounds] 
	 */
	resetCameraClippingRange(bounds?: Bounds): boolean;

	/**
	 * Get the number of visible actors.
	 */
	visibleActorCount(): number;

	/**
	 * Not Implemented yet
	 */
	updateGeometry(): any;

	/**
	 * Ask the active camera to do whatever it needs to do prior to rendering.
	 */
	updateCamera(): boolean;

	/**
	 * Ask the lights in the scene that are not in world space
	 * (for instance, Headlights or CameraLights that are attached to the
	 * camera) to update their geometry to match the active camera.
	 */
	updateLightsGeometryToFollowCamera(): void;

	/**
	 * Update the geometry of the lights in the scene that are not in world
	 * space (for instance, Headlights or CameraLights that are attached to the
	 * camera).
	 */
	updateLightGeometry(): boolean;

	/**
	 * Not Implemented yet
	 */
	visibleVolumeCount(): any;

	/**
     * Set the viewport background.
	 *
     * @param {Number} r Defines the red component (between 0 and 1).
     * @param {Number} g Defines the green component (between 0 and 1).
     * @param {Number} b Defines the blue component (between 0 and 1).
     * @param {Number} a Defines the alpha component (between 0 and 1).
     */
	setBackground(r: number, g: number, b: number, a: number): boolean;

	/**
     * Set the viewport background.
	 *
     * @param {Number} r Defines the red component (between 0 and 1).
     * @param {Number} g Defines the green component (between 0 and 1).
     * @param {Number} b Defines the blue component (between 0 and 1).
     */
    setBackground(r: number, g: number, b: number): boolean;

	/**
     * Set the viewport background.
	 *
     * @param {Number[]} background The RGB color array.
     */
    setBackground(background: number[]): boolean;

	/**
	 * Adds an event listener.
	 */
	onEvent(cb: EventHandler, priority?: number): Readonly<vtkSubscription>;
}

/**
 * Method use to decorate a given object (publicAPI+model) with vtkRenderer characteristics.
 *
 * @param publicAPI object on which methods will be bounds (public)
 * @param model object on which data structure will be bounds (protected)
 * @param {IRendererInitialValues} [initialValues] (default: {})
 */
export function extend(publicAPI: object, model: object, initialValues?: IRendererInitialValues): void;

/**
 * Method use to create a new instance of vtkRenderer.
 * @param {IRendererInitialValues} [initialValues] for pre-setting some of its content
 */
export function newInstance(initialValues?: IRendererInitialValues): vtkRenderer;

/** 
 * vtkRenderer is a Viewport designed to hold 3D properties. It contains
 * an instance of vtkCamera, a collection of vtkLights, and vtkActors. It exists
 * within a RenderWindow. A RenderWindow may have multiple Renderers
 * representing different viewports of the Window and Renderers can be layered
 * on top of each other as well.
 */
export declare const vtkRenderer: {
	newInstance: typeof newInstance,
	extend: typeof extend,
};
export default vtkRenderer;
