import { StepLabelProps, StepLabelResult, GameStepState, HistoryInfo, CharacterInterface } from '@drincs/pixi-vn';
import { Container, UPDATE_PRIORITY, ContainerOptions } from 'pixi.js';

type ErrorCodeType = "obsolete_save" | "unknown_element" | "unregistered_element" | "unregistered_asset" | "not_json_serializable" | "not_implemented" | "invalid_usage" | "unhandled_error";

declare global {
    const __VITE__: boolean | undefined;
    const __ROLLUP_PLUGIN__: boolean | undefined;
    const __webpack_require__: unknown;
}

/**
 * This class is used to create a canvas element to add into a Pixi Application.
 * You can use {@link canvas.add()} to add this element into the application.
 * This class should be implemented and the memory method should be overridden.
 * You must use the {@link canvasComponentDecorator} to register the canvas in the game.
 * In Ren'Py is a displayable.
 * @example
 * ```typescript
 * const CANVAS_EXAMPLE_ID = "CanvasExample";
 *
 * \@canvasComponentDecorator({
 *     name: CANVAS_EXAMPLE_ID,
 * })
 * export class CanvasExample extends Container implements CanvasBaseItem<Memory> {
 *     get memory(): Memory {
 *         return {
 *             pixivnId: CANVAS_EXAMPLE_ID,
 *             // ... other properties
 *         }
 *     }
 *     async setMemory(value: Memory) {
 *         // ... set other properties
 *     }
 * }
 * ```
 */
declare class CanvasBaseItem<T2 extends CanvasBaseItemMemory> {
    constructor(..._options: any);
    /**
     * This method return the memory of the canvas element.
     * @throws {PixiError} when the method is not overridden in the subclass.
     */
    get memory(): T2;
    /**
     * This method set the memory of the canvas element.
     * @throws {PixiError} when the method is not overridden in the subclass.
     */
    setMemory(_value: T2): Promise<void> | void;
    /**
     * Get the id of the canvas element. This variable is used in the system to get the canvas element by id
     */
    pixivnId: string;
}

/**
 * Interface for the canvas base memory
 */
interface CanvasBaseItemMemory {
    pixivnId: string;
    /**
     * The index of the container in its parent, if it has one
     */
    index?: number;
    /**
     * The label of the parent container, if it has one
     */
    parentLabel?: string;
    label?: string;
    zIndex?: number;
}

interface CanvasBaseInterface<T2 extends CanvasBaseItemMemory> extends CanvasBaseItem<T2>, Container {
}

/**
 * Result of a {@link StepLabelType} execution.
 *
 * - `StepLabelResult`: a structured result consumed by the narration engine.
 * - `void`: the step completed without returning an explicit result.
 * - `string`: a simple token or message interpreted by higher-level logic.
 *
 * Prefer returning a well-typed {@link StepLabelResult} for anything that
 * needs to be consumed programmatically. Use plain strings only where a
 * lightweight, convention-based signal is sufficient and clearly documented
 * by the surrounding game logic.
 */
type StepLabelResultType = StepLabelResult | void | string;
type StepLabelPropsType<T extends {} = {}> = StepLabelProps & T;
/**
 * StepLabel is a function that will be executed as the game continues.
 */
type StepLabelType<T extends {} = {}> = (props: StepLabelPropsType<T>, info: {
    /**
     * The id of the label.
     */
    labelId: string;
}) => StepLabelResultType | Promise<StepLabelResultType>;

type StorageElementPrimaryType = string | number | boolean | undefined | null | StorageElementPrimaryType[];
type StorageElementInternalType = StorageElementPrimaryType | Record<string | number | symbol, StorageElementPrimaryType> | StorageElementInternalType[];
type NonFunctionStorage = string | number | boolean | undefined | null | NonFunctionStorage[] | {
    [key: string | number | symbol]: NonFunctionStorage;
};
/**
 * StorageElementType are all the types that can be stored in the storage
 */
type StorageElementType = StorageElementInternalType | Record<string | number | symbol, StorageElementInternalType> | {
    [key: string | number | symbol]: StorageElementType;
} | StorageObjectType[] | (StorageElementPrimaryType | StorageElementInternalType | StorageElementType)[] | {
    [key: string | number | symbol]: NonFunctionStorage;
};
/**
 * StorageObjectType are all the types that can be stored in the storage
 */
type StorageObjectType = Record<string | number | symbol, StorageElementType>;

/**
 * Type for on-error handlers. Handlers accept the error object and the step
 * props; they may be synchronous or asynchronous.
 */
type OnErrorHandler = (error: unknown, props: Partial<StepLabelProps>) => void | Promise<void>;

declare class GameUnifier {
    static init(options: {
        /**
         * The navigate function.
         * @param path The path to navigate to.
         * @returns
         */
        navigate?: (path: string) => void | Promise<void>;
        /**
         * This function returns the current step counter. This counter corresponds to the total number of steps that have been executed so far.
         *
         * If your game engine does not have a history of steps, you can return 0.
         */
        getStepCounter: () => number;
        /**
         * This function sets the current step counter.
         *
         * If your game engine does not have a history of steps, you can not set the step counter.
         */
        setStepCounter: (value: number) => void;
        /**
         * This function returns the current state of the game step.
         *
         * If your game engine does not have a history of steps, you can return an empty object.
         */
        getCurrentGameStepState: () => GameStepState;
        /**
         * This function restores the game step state.
         *
         * If your game engine does not have a history of steps, you can return a resolved promise.
         *
         * @param state The state to restore.
         * @param navigate The function to navigate to the restored path.
         */
        restoreGameStepState: (state: GameStepState, navigate: (path: string) => void | Promise<void>) => Promise<void>;
        /**
         * This function returns the number of opened labels.
         *
         * If your game engine does not have a narration system, you can return 0.
         */
        getOpenedLabels: () => number;
        /**
         * This function is called to process the pending navigation requests (continue/back).
         */
        processNavigationRequests: (navigationRequestsCount: number, props: StepLabelPropsType<any>) => {
            newValue: number;
            result: Promise<StepLabelResultType>;
        };
        /**
         * This function returns the value of a variable.
         * @param key The key of the variable.
         * @returns The value of the variable.
         */
        getVariable: <T = StorageElementType>(prefix: string, key: string) => T | undefined;
        /**
         * This function sets the value of a variable.
         * @param key The key of the variable.
         * @param value The value of the variable.
         */
        setVariable: (prefix: string, key: string, value: StorageElementType) => void;
        /**
         * This function removes a variable.
         * @param key The key of the variable.
         */
        removeVariable: (prefix: string, key: string) => void;
        /**
         * This function returns the value of a flag.
         * @param name The name of the flag.
         */
        getFlag: (name: string) => boolean;
        /**
         * This function sets the value of a flag.
         * @param name The name of the flag.
         * @param value The value of the flag.
         */
        setFlag: (name: string, value: boolean) => void;
        /**
         * This function is called after the narration.continue() method is executed.
         *
         * It can be used to clear old temporary variables.
         *
         * @param openedLabelsNumber The number of opened labels.
         */
        onLabelClosing?: (openedLabelsNumber: number) => void;
        /**
         * Add a history step to the history.
         *
         * If your game engine does not have a history of steps, you can return a resolved promise.
         *
         * @param historyInfo The history information.
         * @param opstions Options to add the step.
         */
        addHistoryItem(historyInfo?: HistoryInfo, opstions?: {
            /**
             * If true, the step will not be added to the history if the current step is the same as the last step.
             */
            ignoreSameStep?: boolean;
        }): void;
        /**
         * This function returns the character by its id.
         * @param id The id of the character.
         * @returns The character or undefined if it does not exist.
         */
        getCharacter: (id: string) => CharacterInterface | undefined;
        /**
         * This function is called to animate a component.
         * @param components - The PixiJS component(s) to animate.
         * @param keyframes - The keyframes to animate the component(s) with.
         * @param options - Additional options for the animation, including duration, easing, and ticker.
         * @param priority - The priority of the ticker. @default UPDATE_PRIORITY.NORMAL
         * @returns The id of tickers.
         * @template T - The type of Pixi’VN component(s) being animated.
         */
        animate: <T extends CanvasBaseInterface<any>>(components: T | string | (string | T)[], keyframes: any, options?: any, priority?: UPDATE_PRIORITY) => string | undefined;
    }): void;
    private static _navigate;
    /**
     * The navigate function.
     * @param path The path to navigate to.
     * @returns
     */
    static get navigate(): (path: string) => void | Promise<void>;
    static set navigate(value: (path: string) => void | Promise<void>);
    private static _getStepCounter;
    private static _setStepCounter;
    /**
     * Returns the current step counter. This counter corresponds to the total number of steps that have been executed so far.
     * @throws {PixiError} when `Game.init()` has not been called yet.
     */
    static get stepCounter(): number;
    /**
     * Returns the current state of the game step.
     * @throws {PixiError} when `Game.init()` has not been called yet.
     */
    static set stepCounter(value: number);
    private static _getCurrentGameStepState;
    /**
     * Returns the current state of the game step.
     * @throws {PixiError} when `Game.init()` has not been called yet.
     */
    static get currentGameStepState(): GameStepState;
    private static _restoreGameStepState;
    /**
     * Restores the game step state.
     * @param state The state to restore.
     * @param navigate The function to navigate to the restored path.
     */
    static get restoreGameStepState(): (state: GameStepState, navigate: (path: string) => void | Promise<void>) => Promise<void>;
    private static _getOpenedLabels;
    /**
     * Returns the number of opened labels.
     * @throws {PixiError} when `Game.init()` has not been called yet.
     */
    static get openedLabels(): number;
    private static _onPreContinueHandlers;
    /**
     * Register a handler to run immediately before a narration "continue" operation.
     * Handlers are executed in registration order and may be async. Use
     * `{@link addOnPreContinue}` / `{@link removeOnPreContinue}` to manage them programmatically.
     */
    static addOnPreContinue(handler: () => Promise<void> | void): void;
    static removeOnPreContinue(handler: () => Promise<void> | void): void;
    static clearOnPreContinueHandlers(): void;
    private static runOnPreContinue;
    /**
     * This function is called immediately before a narration "continue" operation.
     */
    static get onPreContinue(): typeof GameUnifier.runOnPreContinue;
    /**
     * Number of pending navigation requests (continue/back).
     * Positive values indicate pending continue requests,
     * negative values indicate pending back requests.
     */
    private static navigationRequestsCount;
    /**
     * Promise-based lock to ensure only one processNavigationRequests executes at a time.
     * This prevents race conditions in the read-modify-write operation.
     */
    private static processNavigationLock;
    /**
     * This function is called to get the number of pending continue requests.
     * Returns a positive count of pending continue requests when navigationRequestsCount is positive.
     * If it is > 0, after the stepsRunning is 0, the next step will be executed.
     */
    static get continueRequestsCount(): number;
    /**
     * This function is called to increase the number of pending continue requests.
     * Note: While the increment operation itself is atomic, the overall navigation
     * processing uses a lock in processNavigationRequests to ensure atomicity of
     * read-modify-write operations across async boundaries.
     * @param amount The number of steps to increase. Default is 1.
     */
    static increaseContinueRequest(amount?: number): void;
    /**
     * This function is called to get the number of pending back requests.
     * Returns the negation of navigationRequestsCount:
     * - Positive value (absolute value of navigationRequestsCount) when navigationRequestsCount is negative (back requests pending)
     * - Negative value when navigationRequestsCount is positive (continue requests pending)
     * - Zero when navigationRequestsCount is zero (no requests pending)
     * If it is > 0, after the stepsRunning is 0, the previous step will be executed.
     */
    static get backRequestsCount(): number;
    /**
     * This function is called to increase the number of pending back requests.
     * Note: While the decrement operation itself is atomic, the overall navigation
     * processing uses a lock in processNavigationRequests to ensure atomicity of
     * read-modify-write operations across async boundaries.
     * @param amount The number of steps to increase. Default is 1.
     */
    static increaseBackRequest(amount?: number): void;
    private static _processNavigationRequests;
    /**
     * This function processes the pending navigation requests (continue/back).
     * @throws {PixiError} when `Game.init()` has not been called yet.
     */
    static processNavigationRequests(props: StepLabelPropsType<any>): Promise<StepLabelResultType>;
    private static _getVariable;
    /**
     * This function returns the value of a variable.
     * @param key The key of the variable.
     * @returns The value of the variable.
     */
    static get getVariable(): <T = StorageElementType>(prefix: string, key: string) => T | undefined;
    private static _setVariable;
    /**
     * This function sets the value of a variable.
     * @param key The key of the variable.
     * @param value The value of the variable.
     */
    static get setVariable(): (prefix: string, key: string, value: StorageElementType) => void;
    private static _removeVariable;
    /**
     * This function removes a variable.
     * @param key The key of the variable.
     */
    static get removeVariable(): (prefix: string, key: string) => void;
    private static _getFlag;
    /**
     * This function returns the value of a flag.
     * @param name The name of the flag.
     */
    static get getFlag(): (name: string) => boolean;
    private static _setFlag;
    /**
     * This function sets the value of a flag.
     * @param name The name of the flag.
     * @param value The value of the flag.
     */
    static get setFlag(): (name: string, value: boolean) => void;
    private static _onLabelClosing;
    /**
     * This function is called after the narration.continue() method is executed
     * It can be used to clear old temporary variables.
     * @param openedLabelsNumber The number of opened labels.
     */
    static get onLabelClosing(): (openedLabelsNumber: number) => void;
    private static _addHistoryItem;
    /**
     * Add a history step to the history.
     * @param historyInfo The history information.
     * @param opstions Options to add the step.
     */
    static get addHistoryItem(): (historyInfo?: HistoryInfo, opstions?: {
        /**
         * If true, the step will not be added to the history if the current step is the same as the last step.
         */
        ignoreSameStep?: boolean;
    }) => void;
    /**
     * Count of currently executing steps.
     * If a step triggers a narration.continue(), this number is greater than 1.
     */
    static runningStepsCount: number;
    private static _getCharacter;
    /**
     * This function returns the character by its id.
     * @param id The id of the character.
     * @returns The character or undefined if it does not exist.
     */
    static get getCharacter(): (id: string) => CharacterInterface | undefined;
    static onEnd?: StepLabelType;
    private static _onErrorHandlers;
    static addOnError(handler: OnErrorHandler): () => void;
    static removeOnError(handler: OnErrorHandler): void;
    static clearOnErrorHandlers(): void;
    static runOnError(error: unknown, props: StepLabelPropsType<any> | {}): Promise<void>;
    private static _animate;
    /**
     * This function is called to animate a component.
     * @param components - The PixiJS component(s) to animate.
     * @param keyframes - The keyframes to animate the component(s) with.
     * @param options - Additional options for the animation, including duration, easing, and ticker.
     * @param priority - The priority of the ticker. @default UPDATE_PRIORITY.NORMAL
     * @returns The id of tickers.
     * @template T - The type of Pixi’VN component(s) being animated.
     */
    static get animate(): <T extends CanvasBaseInterface<any>>(components: T | string | (string | T)[], keyframes: any, options?: any, priority?: UPDATE_PRIORITY) => string | undefined;
}

declare class PixiError extends Error {
    code: ErrorCodeType;
    constructor(code: ErrorCodeType, message: string);
    constructor(code: ErrorCodeType, message: string, type: "canvas", data: CanvasBaseItemMemory | (CanvasBaseItemMemory & ContainerOptions), parent?: CanvasBaseItem<any>);
    canvasElementInfo?: CanvasBaseItemMemory;
    parent?: CanvasBaseItem<any>;
}

export { type ErrorCodeType, GameUnifier, type OnErrorHandler, PixiError };
