// ── Shared interfaces ─────────────────────────────────────────────────────────

/** Describes a single auto-listener entry stored in `__listeners`. */
interface JawListenerEntry {
	context?: string;
	handler: ((...args: any[]) => any) | string;
	originalHandler?: string;
	target: "DOM" | "controller" | "component";
	type: "autoListener";
	smartUnlisten?: boolean;
}

/** Describes an item used in array-form calls to `set()`. */
interface JawSetItem {
	name: string;
	value: any;
}

/** Describes an entry in the `__validMethodList` built by `_extractValidMethodList`. */
interface JawValidMethod {
	handlerName: string;
	handlerHolder: Jaw;
	_from?: string;
	depthList?: number[];
	minDepth?: number;
	targetType?: "singleNode" | "multiNode" | "manager";
}


// ── Jaw ───────────────────────────────────────────────────────────────────────

/**
 * Represents an element of the MVC model (View or Controller).
 * Extends the native `EventTarget` and adds Shark-specific methods.
 */
export declare class Jaw extends EventTarget {
	/** Read-only identifier for this Jaw instance. Set from `jawId` in the constructor. */
	readonly className: string;

	/** Read-only identifier alias for `className`. */
	readonly id: string;

	/** If the routing method is set to "url", this will be the URL displayed when this Jaw is active. */
	route: string | null;

	/** Whether this Jaw has been initialized via `init()`. */
	isInitialized: boolean;

	/** The options object used in the most recent open operation. */
	currentOpenOptions: Record<string, any>;

	/**
	 * Reactive proxy over `__store`. Properties defined here trigger auto-render when changed,
	 * if `Shark.settings.enableJawStoreAutoRender` is enabled.
	 */
	$store: Record<string, any>;

	/** @internal Internal data store, backing `$store` and `get()`/`set()`. */
	protected __store: Record<string, any>;

	/** @internal Fields registered for auto-rendering. */
	protected __renderFields: string[];

	/** @internal Map of child templates used during rendering. */
	protected __childTemplates: Record<string, string>;

	/** @internal Map of dynamic data bindings. */
	protected __dynamicDataBindings: Record<string, any>;

	/** @internal Registry of event listeners assigned by `smartListen`. */
	protected __listeners: Record<string, Record<string, JawListenerEntry>>;

	/** @internal Named methods added to this Jaw. */
	protected __methods: Record<string, any>;

	/** @internal View binding map (primary). */
	protected __viewBinds: Record<string, any>;

	/** @internal View binding map (secondary). */
	protected __viewBinds2: Record<string, any>;

	/** @internal Hash map used for change-detection in `__singleSet`. */
	protected __storeHashMap: Map<string, any>;

	/** @internal List of valid handler methods built by `smartListen`. */
	protected __validMethodList?: JawValidMethod[];

	/**
	 * The list of Components currently active on this Jaw.
	 * Use `addComponent` / `addComponents` to modify it.
	 */
	readonly activeComponents: Jaw[];

	/**
	 * Creates a new Jaw instance.
	 *
	 * @param jawId - The identifier for this Jaw. If omitted/null/empty, defaults to the
	 *                camelCase class name of the subclass.
	 */
	constructor(jawId?: string | null);

	/**
	 * @deprecated Pass only `jawId`. The `jawDefinition` parameter will be removed in a future version.
	 */
	// eslint-disable-next-line @typescript-eslint/unified-signatures
	constructor(jawId: string | null | undefined, jawDefinition: object);

	/**
	 * Add a single Component to this Jaw.
	 *
	 * @param component - The Component to add, either as a string ID or a Component instance.
	 *                    Passing a string is deprecated; prefer passing the instance directly.
	 * @returns The updated list of active Components.
	 */
	addComponent(component: Jaw | string): Jaw[];

	/**
	 * Add multiple Components to this Jaw.
	 *
	 * @param components - Array of Components to add (as instances or string IDs).
	 * @returns The updated list of active Components.
	 */
	addComponents(components: (Jaw | string)[]): Jaw[];

	/**
	 * Retrieve one or more values from the internal data store.
	 *
	 * - Called with no arguments: returns the entire `__store` object.
	 * - Called with a string: returns the value for that key.
	 * - Called with an array of strings: returns an array of the corresponding values.
	 */
	get(itemName?: string): any;
	get(itemName: string[]): any[];
	get(itemName: undefined): Record<string, any>;

	/** Called when this Jaw is used for the first time. Override in subclasses. */
	init(): void;

	/** @internal Extracts valid `*Handler` methods from a list of Components, recursively. */
	protected _extractComponentsValidMethodList(
		componentList: Jaw[],
		processedComponentList: string[],
		notProcessedComponentList: string[]
	): JawValidMethod[];

	/** @internal Extracts valid `*Handler` methods from a target object and its prototype chain. */
	protected _extractValidMethodList(targetObject: Jaw): JawValidMethod[];

	/** @internal Initialises Components, calling `init()` on each if not already done. */
	protected _initComponents(componentList?: Jaw[] | null, processedComponentList?: string[]): void;

	/**
	 * Store one or more values in this Jaw's internal data store.
	 *
	 * Accepted signatures:
	 * - `set(name, value)` — set a single named value.
	 * - `set(object)` — merge all properties of the object into the store.
	 * - `set(array)` — each item must have `{ name, value }`.
	 */
	set(nameOrItems: string, value: any): void;
	set(nameOrItems: Record<string, any>): void;
	set(nameOrItems: JawSetItem[]): void;

	/** @internal Sets a single key on the store, returns `1` if the value changed, `0` otherwise. */
	protected __singleSet(name: string, value: any): 0 | 1;

	/**
	 * Dispatch an event from this Jaw using jQuery's `.trigger()`.
	 */
	emit(eventName: string, eventData?: any): JQuery;

	/**
	 * Remove an event listener from this Jaw using jQuery's `.off()`.
	 */
	off(eventName: string, eventHandler: (...args: any[]) => any): JQuery;

	/**
	 * Attach an event listener to this Jaw using jQuery's `.on()`.
	 */
	on(eventName: string, eventHandler: (...args: any[]) => any): JQuery;

	/**
	 * Automatically match and assign DOM and controller event listeners based on the
	 * naming convention `selectorOrControllerName_eventNameHandler`.
	 *
	 * @param container - Optional CSS selector or jQuery selection to restrict parsing scope.
	 * @param selfAssign - If `true`, the container itself is treated as a potential target.
	 */
	smartListen(container?: string | JQuery, selfAssign?: boolean): void;

	/** @internal Experimental v2 of `smartListen`. Work in progress. */
	smartListen2(container?: string | JQuery, selfAssign?: boolean): void;

	/**
	 * Remove all listeners previously assigned by `smartListen`.
	 */
	smartUnlisten(container?: string | JQuery): void;

	/**
	 * Internal tracing utility. Delegates to `Shark.trace` if available.
	 */
	trace(message: any, level?: string): void;

	/**
	 * Update the DOM portions bound to a reference model path after the model's dirty
	 * properties have changed.
	 */
	updateDisplay(referenceModelPath: string, sourceEvent?: Event): void;

	/** @internal Utility to compute the DOM depth of a node (distance from BODY). */
	static __getNodeDepth(node: Node): number;
}


// ── RenderableJaw ─────────────────────────────────────────────────────────────

/**
 * The base class for View, Component and PageTemplate.
 * Adds template management on top of Jaw.
 */
export declare class RenderableJaw extends Jaw {
	/** The default template HTML string (raw, before parsing). */
	templateContent: string;

	/** The type identifier for this class (overridden in subclasses). */
	type: string;

	/**
	 * Map of all registered templates, keyed by name.
	 * Each entry contains `{ content, parsed, parsedContent }`.
	 * The default template is stored under the key `"__default__"`.
	 * Non-configurable, non-writable (contents are mutable).
	 */
	readonly templates: Record<string, { content: string; parsed: boolean; parsedContent: string }>;

	/**
	 * Map of fully-expanded template strings keyed by name.
	 * Populated by `parseTemplates()`. The default template is under `"__default__"`.
	 * Non-configurable, non-writable (contents are mutable).
	 */
	readonly parsedTemplates: Record<string, string>;

	/**
	 * The parsed default template string.
	 * @deprecated Prefer `parsedTemplates["__default__"]`. Kept for back-compat.
	 */
	protected __parsedTemplate: string | null;

	/**
	 * `true` after `parseTemplates()` has run at least once.
	 * @deprecated Prefer checking `templates["__default__"].parsed`. Kept for back-compat.
	 */
	protected __templatesParsed?: boolean;

	/** @internal Raw template map (legacy). Prefer `templates`. */
	protected __templates: Record<string, string>;

	constructor(jawId?: string | null);

	/** @deprecated Pass only `jawId`. */
	// eslint-disable-next-line @typescript-eslint/unified-signatures
	constructor(jawId: string | null | undefined, jawDefinition: object);

	/**
	 * Add a named HTML template to this RenderableJaw.
	 *
	 * @param name - Template name. Pass `""` to register the default template (only one allowed).
	 *               Cannot be `"__default__"` (reserved) or contain spaces.
	 * @param content - The raw HTML template string.
	 * @returns The internal `__templates` map, or `undefined` if validation failed.
	 */
	addTemplate(name: string, content: string): Record<string, string> | undefined;

	/**
	 * Set the default HTML template for this RenderableJaw.
	 * Shorthand for `addTemplate("", content)`.
	 *
	 * @param content - The raw HTML template string.
	 * @returns The internal `__templates` map, or `undefined` if validation failed.
	 */
	setTemplate(content: string): Record<string, string> | undefined;

	/**
	 * Parse all registered templates, resolving:
	 * - PageTemplate slot injection (`<shark-template>`)
	 * - Component expansion (`<shark-xxx-component>`) including named slot content and `prop-*` attributes
	 * - `data-sh-model` → `data-shguid` binding
	 * - Auto-bound Shark `$store` properties
	 * - `SmartModel` bound properties
	 * - Dynamic sections (`<shark-section>`)
	 * - `[[renderer.field]]` syntax
	 *
	 * This is a no-op if the template has already been parsed, unless `force: true` is passed.
	 * Called automatically by `PreactRenderer.render()` before the first render.
	 *
	 * @param options.force - If `true`, re-parses even already-parsed templates. Default: `false`.
	 * @param options.sharkModelGuidPlaceHolder - Placeholder for `data-shguid` on Mustache model refs.
	 *   Default: `"__ph__"`.
	 */
	parseTemplates(options?: { force?: boolean; sharkModelGuidPlaceHolder?: string }): void;
}


// ── Component ─────────────────────────────────────────────────────────────────

/**
 * The class to extend to create Component classes.
 * Components are sub-parts of a View, used to render and manage portions of the UI.
 *
 * A Component's HTML template can contain:
 * - `<slot name="..."></slot>` placeholders, filled at the call site with named slot content.
 * - `{{props.xxx}}` placeholders, filled with values passed via `prop-xxx="value"` attributes.
 */
export declare class Component extends RenderableJaw {
	/** Always `"component"` — non-writable and non-configurable. */
	readonly type: "component";

	/**
	 * Props passed to this component instance at the call site via `prop-*` attributes.
	 * Populated at render time; writable.
	 */
	props: Record<string, any>;

	/**
	 * Creates a new Component instance and automatically registers it with Shark
	 * via `Shark.registerComponent()`.
	 *
	 * @param jawId - Identifier for this Component. Defaults to the camelCase subclass name.
	 */
	constructor(jawId?: string | null);

	/** @deprecated Pass only `jawId`. */
	// eslint-disable-next-line @typescript-eslint/unified-signatures
	constructor(jawId: string | null | undefined, jawDefinition: object);
}


// ── Controller ────────────────────────────────────────────────────────────────

/**
 * The class to extend to create Controller classes.
 * Controllers manage application logic and are registered globally with Shark.
 */
export declare class Controller extends Jaw {
	/** Always `"controller"` — non-writable and non-configurable. */
	readonly type: "controller";

	/**
	 * Creates a new Controller instance and automatically registers it with Shark
	 * via `Shark.registerController()`.
	 *
	 * @param jawId - Identifier for this Controller. Defaults to the camelCase subclass name.
	 */
	constructor(jawId?: string | null);

	/** @deprecated Pass only `jawId`. */
	// eslint-disable-next-line @typescript-eslint/unified-signatures
	constructor(jawId: string | null | undefined, jawDefinition: object);
}


// ── PageTemplate ──────────────────────────────────────────────────────────────

/**
 * The class to extend to create PageTemplate classes.
 * A PageTemplate defines a shared layout shell with named `<slot>` placeholders
 * that individual Views fill via `<shark-template name="..." slot="...">`.
 *
 * PageTemplates can only have a single template — use `setTemplate()`.
 * Calling `addTemplate()` throws an error.
 */
export declare class PageTemplate extends RenderableJaw {
	/** Always `"pageTemplate"` — non-writable and non-configurable. */
	readonly type: "pageTemplate";

	/**
	 * Creates a new PageTemplate instance.
	 *
	 * @param jawId - Identifier for this PageTemplate. Defaults to the camelCase subclass name.
	 */
	constructor(jawId?: string | null);

	/**
	 * @throws Always throws — PageTemplates support only one template. Use `setTemplate()`.
	 */
	addTemplate(name: string, content: string): never;
}


// ── View ──────────────────────────────────────────────────────────────────────

/**
 * The class to extend to create View classes.
 * A View can only have a single template; use `setTemplate()` to set it.
 */
export declare class View extends RenderableJaw {
	/**
	 * The main route associated with this View.
	 * @deprecated In favour of the SwimWay router.
	 */
	$mainRoute: string;

	/** Always `"view"` — non-writable and non-configurable. */
	readonly type: "view";

	/**
	 * Creates a new View instance and automatically registers it with Shark
	 * via `Shark.registerView()`.
	 *
	 * @param jawId - Identifier for this View. Defaults to the camelCase subclass name.
	 */
	constructor(jawId?: string | null);

	/** @deprecated Pass only `jawId`. */
	// eslint-disable-next-line @typescript-eslint/unified-signatures
	constructor(jawId: string | null | undefined, jawDefinition: object);

	/**
	 * @deprecated Views support only one template. Use `setTemplate()` instead.
	 * This override ignores `name` and delegates to `setTemplate(content)`.
	 */
	addTemplate(name: string, content: string): Record<string, string> | undefined;
}


// ── Shark ─────────────────────────────────────────────────────────────────────

export declare class Shark {
	// ── Trace level constants ─────────────────────────────────────────────────
	static readonly TRACE_ERROR: "error";
	static readonly TRACE_INFO: "info";
	static readonly TRACE_LOG: "log";
	static readonly TRACE_NONE: "none";
	static readonly TRACE_WARN: "warn";

	// ── Global state ──────────────────────────────────────────────────────────

	/** The global reactive store. Properties set here trigger auto-render on bound Views. */
	static $store: Record<string, any>;

	/** The currently active page descriptor. */
	static activePage: { id: string };

	/** Application-level data bag. */
	static appData: Record<string, any>;

	/** Whether Shark has been initialized. */
	static isInitialized: boolean;

	/** Localization labels. */
	static labels: Record<string, any>;

	/** Registered page templates, keyed by name. */
	static pageTemplates: Record<string, PageTemplate>;

	/** Current trace level. Defaults to `TRACE_WARN`. */
	static traceLevel: string;

	// ── Lifecycle ─────────────────────────────────────────────────────────────

	/**
	 * Initialize the Shark framework.
	 *
	 * @param options.labels - Localization labels object.
	 * @param options.remoteCallTimeOutDuration - Milliseconds before aborting remote calls. Default: 15000.
	 * @param options.templateRenderer - Renderer class to use. Default: PreactRenderer.
	 * @param forceReinit - If `true`, re-runs initialization even if already done.
	 */
	static init(options?: {
		labels?: Record<string, any>;
		remoteCallTimeOutDuration?: number;
		templateRenderer?: any;
		[key: string]: any;
	}, forceReinit?: boolean): void;

	/**
	 * Render the given jaw (or the current active View if omitted) to the screen.
	 *
	 * @param currJaw - The jaw to render. Defaults to the currently active View.
	 * @param options - Renderer options passed through to the active renderer.
	 */
	static render(currJaw?: Jaw, options?: Record<string, any>): boolean;

	// ── Navigation ────────────────────────────────────────────────────────────

	/**
	 * Open a registered View, making it the active page.
	 *
	 * @param pageIdOrJaw - The View instance or its string ID.
	 * @param options - Options forwarded to the View's `open()` / `init()` lifecycle.
	 */
	static openPage(pageIdOrJaw: string | Jaw, options?: Record<string, any>): boolean;

	/**
	 * Activate a View without necessarily making it the visible page.
	 */
	static activateView(pageIdOrJaw: string | Jaw, options?: Record<string, any>): boolean;

	/**
	 * Navigate to a SwimWay route.
	 *
	 * @param route - The route string or SwimRoute object to navigate to.
	 */
	static navigateToRoute(route: string | object): void;

	/**
	 * Parse the current `document.location` and return the View name encoded in the URL.
	 */
	static parseRequestedViewFromLocation(): string;

	// ── Store ─────────────────────────────────────────────────────────────────

	/**
	 * Retrieve one or more values from the global store.
	 *
	 * @param itemName - Key name or array of key names. If omitted, returns the whole store.
	 */
	static get(itemName?: string | string[]): any;

	/**
	 * Set one or more values on the global store.
	 * Triggers auto-render on any Views that reference the changed keys.
	 *
	 * @param nameOrObject - Property name or plain object of `{ name: value }` pairs.
	 * @param value - Value to assign (only used when `nameOrObject` is a string).
	 */
	static set(nameOrObject: string | Record<string, any>, value?: any): any;

	// ── Registration ──────────────────────────────────────────────────────────

	/** Register a Component so it can be referenced in templates. */
	static registerComponent(jaw: Component): void;

	/** Register a Controller. */
	static registerController(jaw: Controller): void;

	/** Register a SmartModel class under a given name. */
	static registerModel(modelName: string, modelClass: typeof SmartModel): void;

	/**
	 * Register a PageTemplate so Views can reference it by name.
	 * Call this after `setTemplate()` on the PageTemplate instance.
	 */
	static registerPageTemplate(jaw: PageTemplate): void;

	/** Register a View so it can be opened via `openPage()`. */
	static registerView(jaw: View): void;

	// ── Model helpers ─────────────────────────────────────────────────────────

	/**
	 * Return a new instance of a registered model, optionally pre-populated with data.
	 *
	 * @param modelNameOrClass - The registered name string or the model class itself.
	 * @param modelData - Data to import into the new instance.
	 */
	static getInstance(modelNameOrClass: string | typeof SmartModel, modelData?: object): SmartModel;

	/**
	 * Return an array of model instances from an array of data objects.
	 */
	static getInstanceList(modelNameOrClass: string | typeof SmartModel, dataList: object[]): SmartModel[];

	/**
	 * Retrieve a model instance registered in the global store by dot-notation path.
	 */
	static getReferenceModel(path: string): SmartModel | null;

	// ── Utilities ─────────────────────────────────────────────────────────────

	/** Bind a View's DOM to a model using a CSS container selector. */
	static bindViewToModel(containerCSSSelector: string): void;

	/** Generate a UUID string. */
	static generateUUID(): string;

	/**
	 * Emit a trace message if the current `traceLevel` allows it.
	 *
	 * @param args - Message and optional data to log.
	 */
	static trace(...args: any[]): void;

	/**
	 * Return `true` if the given level should be emitted at the current `traceLevel`.
	 */
	static shouldTrace(level: string): boolean;

	/**
	 * Update URLSearchParams in the current URL without adding a browser history entry.
	 */
	static setURLSearchParams(
		urlSearchParams: string | object | URLSearchParams | null,
		replace?: boolean,
		routeObject?: object | null
	): void;
}


// ── SmartModel ────────────────────────────────────────────────────────────────

/** Describes a single dirty property entry, tracking the original value before changes. */
interface SmartModelDirtyEntry {
	property: string;
	originalValue: any;
}

/** Options accepted by `export` / `__export`. */
interface SmartModelExportOptions {
	/** If provided, only the listed property names will be exported. */
	fields?: string[];
}

/** Options accepted by `import` / `__import`. */
interface SmartModelImportOptions {
	/** If `true`, properties present in `data` but missing on the model will be created. Default: `false`. */
	createMissingProperties?: boolean;
	/** If `true`, empty/falsy values in `data` are still matched onto the model. Default: `true`. */
	matchEmptyParameters?: boolean;
}

/** Options accepted by `importField`. */
interface SmartModelImportFieldOptions {
	/** If `true`, `undefined`/`null` values are accepted. Default: `false`. */
	acceptUndefined?: boolean;
	/** Explicit data type for parsing. `"auto"` performs no conversion. Default: `"auto"`. */
	dataType?: "auto" | "boolean" | "date" | "number";
	/** Fallback value used when the parsed number is `NaN`. Only for `dataType: "number"`. */
	defaultValue?: number;
	/** If `true`, date values are parsed as UTC and converted to local time. Default: `true`. */
	useUTC?: boolean;
}

/**
 * Payload dispatched with `"dataChanged"` and `"<propertyName>Changed"` events.
 */
interface SmartModelChangeEventData {
	/** The `__modelName` of the model that triggered the change. */
	modelName: string | undefined;
	/** The new value assigned to the property. */
	newValue: any;
	/** The previous value of the property before the change. */
	oldValue: any;
	/** The dot-notation path of the property that changed. */
	property: string;
}

/** Describes an item used in array-form calls to `set()`. */
interface SmartModelSetItem {
	name: string;
	value: any;
}

/** Inferred type map produced by `SmartModel.inferTypes()`. */
type SmartModelInferredTypes = Record<
	string,
	"number" | "datetime" | "boolean" | "string" | "array" | "object" | typeof SmartModel
>;

/**
 * Base class for reactive data models in the Shark MVC framework.
 *
 * @fires SmartModel#dataChanged - Emitted whenever a property changes value.
 * @fires SmartModel#<propertyName>Changed - Emitted for the specific changed property.
 */
export declare class SmartModel extends EventTarget {
	/** Unique GUID assigned at construction. Non-writable. */
	readonly __shguid: string;

	/** Whether any property of this model differs from its original/cleaned value. */
	__isDirty: boolean;

	/** List of properties that have changed since the last `clean()` call. */
	__dirtyProperties: SmartModelDirtyEntry[];

	/** Auto-bound property names (reserved for internal use). */
	__boundProperties: string[];

	/** The model structure passed at construction, if any. */
	__modelStructure: object | undefined;

	/** The renderer instance associated with this model. */
	__renderer: any;

	// ── Private methods exposed via Object.defineProperty ────────────────────

	protected readonly __clean: (properties?: string[]) => SmartModelDirtyEntry[];
	protected readonly __export: (options?: SmartModelExportOptions) => Record<string, any>;
	protected readonly __import: (data: object, options?: SmartModelImportOptions) => any;
	protected readonly __restore: (properties?: string[]) => void;
	protected readonly __setPropertyDirtiness: (propertyName: string, eventData: SmartModelChangeEventData) => void;
	protected readonly __toJSON: (forcePrivateProperties?: boolean) => Record<string, any>;

	/**
	 * Creates a new SmartModel instance.
	 */
	constructor(data?: object, options?: SmartModelImportOptions, modelStructure?: object);

	/** Replace the renderer instance for this model. */
	addRenderer(renderer: { setModel(model: SmartModel): void; [key: string]: any }): void;

	/**
	 * Clear dirty state for all properties, or only the specified ones.
	 * After this call, `__isDirty` is recomputed.
	 */
	clean(properties?: string[]): SmartModelDirtyEntry[];

	/** Dispatch an event from this model using jQuery's `.trigger()`. */
	emit(eventName: string, eventData?: any): JQuery;

	/**
	 * Export all public, non-function properties to a plain object.
	 * Properties starting with `__` or `jQuery` are excluded by default.
	 */
	export(options?: SmartModelExportOptions): Record<string, any>;

	/** Export an array field as a JSON string. */
	exportArrayField(field: string, format?: "JSON"): string;
	protected __exportArrayField(field: string, format?: "JSON"): string;

	/** Export a boolean field as a number (`1`/`0`) or string. */
	exportBooleanField(field: string, format?: "number" | "string"): number | string;
	protected __exportBooleanField(field: string, format?: "number" | "string"): number | string;

	/** Export a date field as a formatted string. */
	exportDateField(field: string, format?: "ISO", useUTC?: boolean): string;
	protected __exportDateField(field: string, format?: "ISO", useUTC?: boolean): string;

	/** Export a numeric field, parsing strings to floats if necessary. */
	exportNumberField(field: string, format?: string): number;
	protected __exportNumberField(field: string, format?: string): number;

	/** Export an object field as a JSON string. */
	exportObjectField(field: string, format?: "JSON"): string;
	protected __exportObjectField(field: string, format?: "JSON"): string;

	/** Import data from a plain object onto this model. */
	import(data: object, options?: SmartModelImportOptions): any;

	/** Import and parse a boolean field from a raw value. */
	importBooleanField(field: string, value: any): boolean;
	protected __importBooleanField(field: string, value: any): boolean;

	/** Import and parse a date field, converting it to a `moment` object. */
	importDateField(field: string, value: any, useUTC?: boolean): boolean;
	protected __importDateField(field: string, value: any, useUTC?: boolean): boolean;

	/** Import and parse a numeric field. */
	importNumberField(field: string, value: any, defaultValue?: number): boolean;
	protected __importNumberField(field: string, value: any, defaultValue?: number): boolean;

	/**
	 * Unified import helper that dispatches to the correct typed import method
	 * based on `options.dataType`.
	 */
	importField(field: string, value: any, options?: SmartModelImportFieldOptions): boolean;

	/**
	 * Inspect an instance of this model class and infer the data type of each public property.
	 * Results are also logged to the console.
	 */
	static inferTypes(): void;

	/**
	 * Check whether this model has unsaved/unclean property changes.
	 *
	 * @param properties - A single property path or array of paths to check.
	 * @param mode - `"any"` (default): `true` if at least one listed property is dirty.
	 *               `"all"`: `true` only if every listed property is dirty.
	 */
	isDirty(properties?: string | string[] | null, mode?: "any" | "all"): boolean;

	/** Remove an event listener from this model using jQuery's `.off()`. */
	off(eventName: string, eventHandler: (...args: any[]) => any): JQuery;

	/** Attach an event listener to this model using jQuery's `.on()`. */
	on(eventName: string, eventHandler: (...args: any[]) => any): JQuery;

	/**
	 * Register a property as bound to a View (called internally by `parseTemplates`).
	 *
	 * @param propertyName - The model property name.
	 * @param viewClassName - The `className` of the View that references this property.
	 */
	registerBoundProperty(propertyName: string, viewClassName: string): void;

	/** Restore dirty properties to their original values and reset `__isDirty` to `false`. */
	restore(properties?: string[]): void;

	protected __singleSet(name: string, value: any, eventTargetNode?: Element | null): void;

	/**
	 * Assign a value to one or more model properties.
	 *
	 * @fires SmartModel#dataChanged
	 * @fires SmartModel#<propertyName>Changed
	 */
	set(name: string, value: any, eventTargetNode?: Element | null): void;
	set(name: Record<string, any>, eventTargetNode?: Element | null): void;
	set(name: SmartModelSetItem[], eventTargetNode?: Element | null): void;

	/** Serialize this model to a plain object. */
	toJSON(forcePrivateProperties?: boolean): Record<string, any>;

	/** Serialize this model to a JSON string. */
	toString(forcePrivateProperties?: boolean): string;

	/** @experimental Sync a single property value to all matching `[data-sh-prop]` DOM elements. */
	updateScreenWithModelValue(
		name: string,
		eventTargetNode: Element | null,
		value: any,
		eventData: SmartModelChangeEventData | string
	): void;

	/** @experimental @dangerous Sync all public properties to their matching `[data-sh-prop]` DOM elements. */
	updateScreenWithModelValues(): void;

	// ── Optional lifecycle hooks ──────────────────────────────────────────────

	/** Called whenever any property changes. Override in subclasses. */
	onDataChanged?(eventData: SmartModelChangeEventData): void;

	/** Catch-all index signature for dynamic `on<PropertyName>Changed` hooks. */
	[key: string]: any;
}


// ── SwimRoute ─────────────────────────────────────────────────────────────────

/** Data object accepted by the `SwimRoute` constructor. */
interface SwimRouteData {
	/** Route pattern, optionally containing dynamic segments prefixed with `:` (e.g. `"/user/:id"`). */
	route: string;
	/** The View instance or class associated with this route. */
	view: any;
}

/**
 * Represents a single application route, pairing a URL pattern with a View
 * and providing dynamic parameter extraction.
 */
export declare class SwimRoute {
	/** The route pattern string (e.g. `"/user/:id/orders/:orderId"`). */
	route: string;

	/** The View instance or class associated with this route. */
	view: any;

	/** The last matched URL for this route. */
	url: string;

	/** The dynamic parameters extracted from the last successful `extractRouteParams()` call. */
	readonly params: Record<string, string>;

	constructor(data: SwimRouteData);

	/**
	 * Match a URL against this route's pattern and extract any dynamic segment values.
	 *
	 * @param url - The URL to match. Falls back to `this.url` if omitted.
	 */
	extractRouteParams(url?: string): void;
}


// ── SwimWay ───────────────────────────────────────────────────────────────────

/**
 * The basic router for the Shark environment.
 * Fun Fact: "SwimWay" is the name given by researchers to a route followed in the ocean by sharks.
 */
export declare class SwimWay {
	/**
	 * @param routingMethod - One of `"pathname"` (default), `"url"`, or `"hash"`.
	 */
	constructor(routingMethod?: "pathname" | "url" | "hash");

	/** Add a single route. Returns the new total number of routes. */
	addRoute(route: SwimRouteData | SwimRoute): number;

	/** Add multiple routes at once. Returns the new total number of routes. */
	addRoutes(routes: (SwimRouteData | SwimRoute)[]): number;

	/** Navigate to a route by path string or SwimRoute object. */
	navigateTo(route: string | SwimRoute): boolean;

	/**
	 * Parse `document.location` and return the View name encoded in the current URL.
	 */
	getRequestedViewFromLocation(): string;

	/**
	 * Update URLSearchParams in the current URL without creating a new browser history entry.
	 *
	 * @param urlSearchParams - A string, plain object, or `URLSearchParams` instance.
	 */
	setURLSearchParams(urlSearchParams: string | object | URLSearchParams): void;
}


// ── Utils ─────────────────────────────────────────────────────────────────────

export declare class Utils {
	/**
	 * Return a random number between 0 and `max`, or between `minOrMax` and `max`.
	 */
	static betterRandom(minOrMax: number, max?: number): number;

	/**
	 * Return a random integer between 0 and `max`, or between `minOrMax` and `max`.
	 */
	static betterRandomInt(minOrMax: number, max?: number): number;

	/** Convert a camelCase string to dash-separated lowercase words. */
	static camelToDashed(inputString: string): string;

	/** Compute a simple numeric hash of any serializable value. */
	static computeHash(value: any): number;

	/** Convert a dash-separated string to camelCase. */
	static dashedToCamel(inputString: string): string;

	/** Decode common HTML entities in a string. */
	static decodeHtmlEntities(str: string): string;

	/** Deep-merge any number of objects into a new object. */
	static deepMerge(...objects: object[]): object;

	/** Return an object containing only the properties that differ between two objects. */
	static extractDifferentProperties(firstObject: object, secondObject: object): object;

	/**
	 * Parse the attributes of an HTML opening tag string into a plain object.
	 *
	 * - `data-*` attributes are grouped under `result.dataset` (camelCase keys, no `data-` prefix).
	 * - `prop-*` attributes are grouped under `result.props` (camelCase keys, no `prop-` prefix).
	 *   These are **not** passed to the HTML tag root; they are used exclusively for `{{props.xxx}}`
	 *   interpolation in component templates.
	 * - All other attributes are returned as camelCase top-level keys.
	 */
	static extractPropertiesFromHTMLString(html: string): {
		dataset?: Record<string, any>;
		props?: Record<string, any>;
		[key: string]: any;
	};

	/**
	 * Extract all top-level `<shark-xxx>` component tags from a template string.
	 *
	 * Unlike a simple regex, this function correctly handles nested shark components
	 * by counting open/close depth, so slot content containing other `<shark-yyy>` tags
	 * is never truncated.
	 *
	 * @param template - The HTML template string to scan.
	 * @returns Array of full tag strings for every top-level shark component found.
	 */
	static extractSharkComponentTags(template: string): string[];

	/** Flatten a nested object into a single-level object (non-recursive values only). */
	static flatten(objectToFlatten: object): object;

	/** Generate a random GUID string, optionally with a prefix and/or suffix. */
	static generateGUID(prefix?: string, suffix?: string): string;

	/**
	 * Get a property value from an object by dot-notation path.
	 * Returns `undefined` if the path does not exist.
	 */
	static getDeepProperty(object: object, path: string): any;

	/**
	 * Cross-reference `sourceList` items against named lookup lists, attaching matched
	 * objects as `__<propertyName>` properties (looks for `*Guid` properties as foreign keys).
	 */
	static matchLists(sourceList: any[], matchLists: Record<string, any[]>, options?: object): void;

	/**
	 * Copy properties from `sourceObject` onto `targetObject`, with configurable rules
	 * for missing properties, empty values, and undefined values.
	 */
	static matchProperties(
		targetObject: object,
		sourceObject: object,
		options?: {
			createMissingProperties?: boolean;
			matchEmptyParameters?: boolean;
			matchUndefinedParameters?: boolean;
			exclude?: string[];
		}
	): void;

	/**
	 * Merge the attributes of `includeTag` onto the root element of `templateHtml`.
	 *
	 * - `class` values are concatenated.
	 * - `style` values are merged (includeTag wins on conflicts).
	 * - `data-*` attributes are merged (includeTag wins on conflicts).
	 * - `prop-*` attributes are **excluded** — they are never serialized onto the HTML tag.
	 * - All other attributes are overwritten by `includeTag`.
	 */
	static mergeAttributes(templateHtml: string, includeTag: string): string;

	/** Merge two inline style strings, with `includeStyle` winning on conflicts. */
	static mergeStyle(templateStyle: string, includeStyle: string): string;

	/** Move the caret to the end of an input or textarea element. */
	static moveCaretToEnd(target: HTMLInputElement | HTMLTextAreaElement): void;

	/** Flatten a (possibly nested) object into an array of dot-notation property paths. */
	static objectToFlatMap(object: object, parent?: string): string[];

	/** Safely parse a JSON string, returning a typed fallback on failure. */
	static parseJSON(data: string, expectedType?: "array" | "object" | string): any;

	/** Add `_index` and `_displayIndex` properties to every item in an array (mutates in place). */
	static reindexList(list: any[]): void;

	/**
	 * Replace `null` or `undefined` values in an object or array with `replaceVal` (mutates in place).
	 */
	static replaceNullValue(objectToParse: object | any[], replaceVal: any): void;

	/**
	 * Resolve named slot content and `prop-*` interpolation for a component template.
	 *
	 * Given the component's own template HTML and the full usage tag from the parent
	 * template, this function:
	 * 1. Extracts `<slot name="...">content</slot>` children from the usage tag and
	 *    substitutes them into matching `<slot name="..."></slot>` placeholders in the
	 *    component template.
	 * 2. Extracts `prop-*` attributes from the usage tag and substitutes them into
	 *    `{{props.xxx}}` placeholders in the component template.
	 *
	 * Unmatched slots and unmatched `{{props.xxx}}` placeholders are left unchanged
	 * as implicit fallback content.
	 *
	 * @param componentTemplate - The component's own HTML template string.
	 * @param componentUsageTag - The full usage tag as written in the parent template,
	 *   e.g. `<shark-foo prop-id="bar"><slot name="title">Hi</slot></shark-foo>`.
	 * @returns The resolved template string.
	 */
	static resolveComponentSlots(componentTemplate: string, componentUsageTag: string): string;

	/** JSON-stringify a value, safely handling circular references and `Map` instances. */
	static safeStringify(sourceValue: any): string;

	/**
	 * Shorthand for `searchArrayForProperty`.
	 */
	static safp(
		list: any[],
		property: string,
		value: any,
		searchType?: boolean | "first" | "all" | "index"
	): object | any[] | number | null;

	/**
	 * Search an array for the first object (or all objects) whose named property equals `value`.
	 *
	 * @param searchType - `"first"` (default): return the first match.
	 *                     `"all"`: return an array of all matches.
	 *                     `"index"`: return the index of the first match.
	 *                     Passing `true` is equivalent to `"first"`; `false` to `"all"`.
	 */
	static searchArrayForProperty(
		list: any[],
		property: string,
		value: any,
		searchType?: boolean | "first" | "all" | "index"
	): object | any[] | number | null;

	/**
	 * Assign a value to a property on an object, creating intermediate objects as needed.
	 */
	static setDeepProperty(object: object, path: string, value: any, depth?: number): object;

	/** Legacy trace utility. Prefer `Shark.trace()`. */
	static trace(content: string): void;

	/** Lowercase the first character of a string. */
	static toCamelCase(value: string): string;

	/** Uppercase the first character of a string, optionally lowercasing the rest. */
	static toTitleCase(value: string, forceLowerCase?: boolean): string;

	/** Pad a number with leading zeros to a given total length. */
	static zeroFill(number: number, length: number): string;
}