/**
 * additional import for TypeScript
 * @import Renderer from "./../video/renderer.js";
 */

// `Camera2d` is type-only here — `cameraClass` accepts the constructor
// shape but this file never instantiates one. Importing as a value
// would pull the Camera module into the runtime graph along the
// `application → defaultApplicationSettings → settings` chain, opening
// a circular-import surface. Type-only import compiles away.
import type Camera2d from "../camera/camera2d";
import { RendererType } from "../const";
import { PhysicsAdapter } from "../physics/adapter";
import Renderer from "../video/renderer";
import { Batcher } from "../video/webgl/batchers/batcher";
import { ScaleMethod } from "./scaleMethods";

type BlendMode = "normal" | "multiply" | "lighter" | "additive" | "screen";

/**
 * How the application's physics is configured.
 *
 * - `"builtin"` (default): auto-construct a {@link BuiltinAdapter} with default options.
 * - `"none"`: keep an adapter for API compatibility but skip the per-frame `step()` call (frozen world).
 * - `PhysicsAdapter` instance: use the given adapter (e.g. `new BuiltinAdapter({ gravity })`,
 *   or `new MatterAdapter()` from `@melonjs/matter-adapter`).
 * - `{ adapter: PhysicsAdapter }`: explicit form, reserved for future per-app physics options.
 */
type PhysicsType =
	| "builtin"
	| "none"
	| PhysicsAdapter
	| { adapter: PhysicsAdapter };

type PowerPreference = "default" | "low-power";

export type ApplicationSettings = {
	/**
	 * Renderer to use. Three built-in modes (constants from `me.video`):
	 *
	 * - {@link CANVAS} — HTML5 Canvas backend. No shader / mesh /
	 *   Camera3d support.
	 * - {@link WEBGL} — **requires WebGL**. Throws at `new Application(...)`
	 *   time if WebGL is unavailable (driver-blocklisted GPU, perf-caveat
	 *   failure, etc.). Use this when your scene needs Camera3d, Mesh,
	 *   ShaderEffect, Light2d or GPU tilemap — you'd rather fail fast
	 *   than render a stuck blank canvas.
	 * - {@link AUTO} — try WebGL, silently fall back to Canvas if
	 *   unavailable. Application construction always succeeds. The
	 *   WebGL-only subsystems (Camera3d, Mesh, ShaderEffect, Light2d,
	 *   GPU tilemap) silently stop working under the Canvas fallback —
	 *   if your scene depends on any of those, use `WEBGL` instead.
	 *
	 * Or pass a custom `Renderer` subclass instance for full control.
	 * @default AUTO
	 */
	renderer: RendererType | Renderer;

	/**
	 * enable scaling of the canvas ('auto' for automatic scaling)
	 * @default 1
	 */
	scale: number | "auto";

	/**
	 * screen scaling modes
	 * @default "manual"
	 */
	scaleMethod: ScaleMethod;

	/**
	 * the HTML Element to be used as the reference target when using automatic scaling (by default melonJS will use the parent container of the div element containing the canvas)
	 */
	scaleTarget: HTMLElement;

	/**
	 * if true the renderer will only use WebGL 1
	 * @default false
	 */
	preferWebGL1: boolean;

	/**
	 * a hint to the user agent indicating what configuration of GPU is suitable for the WebGL context. To be noted that Safari and Chrome (since version 80) both default to "low-power" to save battery life and improve the user experience on these dual-GPU machines.
	 * @default default
	 */
	powerPreference: PowerPreference;

	/**
	 * whether to allow transparent pixels in the front buffer (screen).
	 * @default false
	 */
	transparent: boolean;

	/**
	 * whether to enable or not video scaling interpolation
	 * @default false
	 */
	antiAlias: boolean;

	/**
	 * whether to display melonJS version and basic device information in the console
	 * @default true
	 */
	consoleHeader: boolean;

	/**
	 * the default blend mode to use ("normal", "multiply", "lighter", "additive", "screen")
	 * @default "normal"
	 */
	blendMode: BlendMode;

	/**
	 * The physics system to use. Accepts:
	 * - `"builtin"` (default) — the built-in SAT physics adapter
	 * - `"none"` — disables physics; `World.step` skips the simulation,
	 *   the world container behaves like a pure scene graph
	 * - a `PhysicsAdapter` instance — e.g. `new MatterAdapter()` from
	 *   `@melonjs/matter-adapter`, or any third-party adapter
	 * - `{ adapter: PhysicsAdapter }` — explicit form, reserved for
	 *   future per-app physics options
	 *
	 * The adapter's `physicLabel` becomes `world.physic` so user code
	 * can branch on the active engine without importing the concrete
	 * adapter class (`app.world.physic === "matter"`, etc.).
	 * @default "builtin"
	 */
	physic: PhysicsType;

	/**
	 * Enable the WebGL2 procedural shader path for orthogonal tile layers.
	 * When `true` (default), eligible layers render via a single quad per
	 * tileset + a fragment shader doing per-fragment GID lookup, bypassing
	 * the per-tile draw loop entirely. Layers that don't qualify
	 * (Canvas/WebGL1, non-orthogonal, collection-of-image tilesets,
	 * tilerendersize "grid", non-zero tileoffset, oversampled beyond the
	 * shader's overflow window) fall back to the legacy path automatically.
	 * Set to `false` to disable globally.
	 * @default true
	 */
	gpuTilemap: boolean;
	/**
	 * if true, the renderer will fail if the browser reports a major performance caveat
	 * (e.g. software WebGL). Set to false to allow WebGL on machines with
	 * blocklisted GPU drivers or software renderers.
	 * @default true
	 */
	failIfMajorPerformanceCaveat: boolean;

	/**
	 * enable high precision shaders (WebGL only).
	 * When false, shaders prefer "mediump" precision for better performance on
	 * some mobile GPUs, falling back to "lowp" if "mediump" is not supported.
	 * When true (default), the highest precision supported by the device is used.
	 * This setting is ignored by the Canvas renderer.
	 * @default true
	 * @example
	 * import { Application, device } from "melonjs";
	 * const app = new Application(800, 600, {
	 *     parent: "screen",
	 *     // prefer lower shader precision on mobile for better performance
	 *     highPrecisionShader: !device.isMobile,
	 * });
	 */
	highPrecisionShader: boolean;

	/**
	 * whether to enable sub-pixel rendering (avoid sprite flickering when using transforms)
	 * @default false
	 */
	subPixel: boolean;

	/**
	 * whether to enable verbose mode (additional console output for debugging)
	 * @default false
	 */
	verbose: boolean;

	/**
	 * whether to enable legacy mode (enables deprecated `video.init()` entry point)
	 * @default false
	 */
	legacy: boolean;

	/**
	 * the CSS background color of the parent element that holds the canvas.
	 * Applied during initialization to prevent a white flash before the first render.
	 * Set to `"transparent"` to disable, or any valid CSS color value.
	 * @default "#000000"
	 */
	backgroundColor: string;

	/**
	 * a custom batcher class (WebGL only)
	 * @deprecated since 18.1.0 — use `batcher` instead
	 */
	compositor?: (new (renderer: any) => Batcher) | undefined;

	/**
	 * a custom batcher class (WebGL only)
	 */
	batcher?: (new (renderer: any) => Batcher) | undefined;

	/**
	 * Default camera class instantiated for any {@link Stage} that does not
	 * explicitly provide its own cameras. Set to {@link Camera3d} to opt
	 * every stage in the app into perspective rendering by default. Stages
	 * can still override per-instance via `super({ cameras: [...] })` or
	 * per-class via `super({ cameraClass: Camera2d })`. Built-in stages
	 * (e.g. the loader screen) explicitly use {@link Camera2d} regardless
	 * of this setting.
	 *
	 * **WebGL requirement.** Camera classes whose
	 * `static defaultSortOn === "depth"` (Camera3d and any subclass) need
	 * the WebGL renderer — perspective projection, depth attachment and
	 * mesh draw all live in the WebGL backend. Pairing such a
	 * `cameraClass` with `renderer: video.AUTO` on a system where AUTO
	 * falls back to Canvas emits a `console.warn` at construction time
	 * and produces a non-functional render. Use `renderer: video.WEBGL`
	 * to get a hard throw instead.
	 * @default Camera2d
	 */
	cameraClass?: new (
		minX: number,
		minY: number,
		maxX: number,
		maxY: number,
	) => Camera2d;
} & (
	| {
			/**
			 * the DOM parent element (or its string ID) to hold the canvas in the HTML file
			 */
			parent: string | HTMLElement;
			canvas?: never;
	  }
	| {
			parent?: never;
			/**
			 * an existing canvas element to use as the renderer target
			 * (by default melonJS will create its own canvas based on given parameters)
			 */
			canvas: HTMLCanvasElement;
	  }
);

/**
 * Resolved application settings after init() has processed the input.
 * Includes computed properties not present in the user-facing settings.
 * @ignore
 */
export type ResolvedApplicationSettings = ApplicationSettings & {
	width: number;
	height: number;
	autoScale: boolean;
	zoomX: number;
	zoomY: number;
	scale: number;
};
