import { Cart } from '@nosto/nosto-js/client';
import { Context } from 'react';
import { PushedCustomer as Customer } from '@nosto/nosto-js/client';
import { JSX } from 'react/jsx-runtime';
import { WebsiteOrder as Order } from '@nosto/nosto-js/client';
import { Product } from '@nosto/nosto-js/client';
import { PushedProduct } from '@nosto/nosto-js/client';
import { ReactElement } from 'react';
import { ReactNode } from 'react';
import { RenderMode } from '@nosto/nosto-js/client';

export { Cart }

export { Customer }

/**
 * You can personalise your cart and checkout pages by using the `Nosto404` component.
 * The component does not require any props.
 *
 * By default, your account, when created, has three 404-page placements named `notfound-nosto-1`, `notfound-nosto-2` and `notfound-nosto-3`.
 * You may omit these and use any identifier you need.
 * The identifiers used here are simply provided to illustrate the example.
 *
 * @example
 * ```
 * <div className="notfound-page">
 *   <NostoPlacement id="notfound-nosto-1" />
 *   <NostoPlacement id="notfound-nosto-2" />
 *   <NostoPlacement id="notfound-nosto-3" />
 *   <Nosto404 />
 * </div>
 * ```
 *
 * @group Components
 */
export declare function Nosto404(props: Nosto404Props): null;

/**
 * @group Hooks
 */
export declare type Nosto404Props = {
    placements?: string[];
};

/**
 * You can personalise your category and collection pages by using the NostoCategory component.
 * The component requires that you provide it the the slash-delimited slug representation of the current category.
 *
 * By default, your account, when created, has two category placements named `categorypage-nosto-1` and `categorypage-nosto-2`.
 * You may omit these and use any identifier you need. The identifiers used here are simply provided to illustrate the example.
 *
 * @example
 * ```
 * <div className="category-page">
 *   <NostoPlacement id="categorypage-nosto-1" />
 *   <NostoPlacement id="categorypage-nosto-2" />
 *   <NostoCategory category={category.name} />
 * </div>
 * ```
 *
 * **Note:** Be sure to pass in the correct category representation.
 * If the category being viewed is `Mens >> Jackets`, you must provide the name as `/Mens/Jackets`.
 * You must ensure that the category path provided here matches that of the categories tagged in your products.
 *
 * @group Components
 */
export declare function NostoCategory(props: NostoCategoryProps): null;

/**
 * @group Hooks
 */
export declare type NostoCategoryProps = {
    category: string;
    placements?: string[];
};

/**
 * You can personalise your cart and checkout pages by using the NostoCheckout component.
 * The component does not require any props.
 *
 * By default, your account, when created, has two cart-page placements named `categorypage-nosto-1` and `categorypage-nosto-2`.
 * You may omit these and use any identifier you need.
 * The identifiers used here are simply provided to illustrate the example.
 *
 * @example
 * ```
 * <div className="checkout-page">
 *   <NostoPlacement id="checkout-nosto-1" />
 *   <NostoPlacement id="checkout-nosto-2" />
 *   <NostoCheckout />
 * </div>
 * ```
 *
 * @group Components
 */
export declare function NostoCheckout(props: NostoCheckoutProps): null;

/**
 * @group Hooks
 */
export declare type NostoCheckoutProps = {
    placements?: string[];
};

/**
 * @group Essential Functions
 */
export declare const NostoContext: Context<NostoContextType>;

/**
 * @group Types
 */
export declare interface NostoContextType {
    account: string;
    clientScriptLoaded: boolean;
    currentVariation?: string;
    renderFunction?: (...args: unknown[]) => unknown;
    responseMode: RenderMode;
    recommendationComponent?: RecommendationComponent;
}

/**
 * The `NostoHome` component must be used to personalise the home page. The component does not require any props.
 *
 * By default, your account, when created, has four front-page placements named `frontpage-nosto-1`, `frontpage-nosto-2`, `frontpage-nosto-3` and `frontpage-nosto-4`.
 * You may omit these and use any identifier you need.
 * The identifiers used here are simply provided to illustrate the example.
 *
 * The `<NostoHome \>` component needs to be added after the placements.
 * Content and recommendations will be rendered through this component.
 *
 * @example
 * ```
 *  <div className="front-page">
 *   <NostoPlacement id="frontpage-nosto-1" />
 *   <NostoPlacement id="frontpage-nosto-2" />
 *   <NostoPlacement id="frontpage-nosto-3" />
 *   <NostoPlacement id="frontpage-nosto-4" />
 *   <NostoHome />
 * </div>
 * ```
 *
 * @group Components
 */
export declare function NostoHome(props: NostoHomeProps): null;

/**
 * @group Hooks
 */
export declare type NostoHomeProps = {
    placements?: string[];
};

/**
 * You can personalise your order-confirmation/thank-you page by using the `NostoOrder` component.
 * The component requires that you provide it with the details of the order.
 *
 * By default, your account, when created, has one other-page placement named `thankyou-nosto-1`.
 * You may omit this and use any identifier you need. The identifier used here is simply provided to illustrate the example.
 *
 * The order prop requires a value that adheres to the type `Purchase`.
 *
 * @example
 * ```
 * <div className="thankyou-page">
 *     <NostoPlacement id="thankyou-nosto-1" />
 *     <NostoOrder order={{ purchase: toOrder(order) }} />
 * </div>
 * ```
 *
 * @group Components
 */
export declare function NostoOrder(props: NostoOrderProps): null;

/**
 * @group Hooks
 */
export declare type NostoOrderProps = {
    order: Order | ToCamelCase<Order>;
    placements?: string[];
};

/**
 * You can personalise your miscellaneous pages by using the NostoOther component.
 * The component does not require any props.
 *
 * By default, your account, when created, has two other-page placements named `other-nosto-1` and `other-nosto-2`.
 * You may omit these and use any identifier you need.
 * The identifiers used here are simply provided to illustrate the example.
 *
 * @example
 * ```
 * <div className="other-page">
 *     <NostoPlacement id="other-nosto-1" />
 *     <NostoPlacement id="other-nosto-2" />
 *     <NostoOther />
 * </div>;
 * ```
 *
 * @group Components
 */
export declare function NostoOther(props: NostoOtherProps): null;

/**
 * @group Hooks
 */
export declare type NostoOtherProps = {
    placements?: string[];
};

/**
 * Nosto React has a special component called NostoPlacement.
 * The component is a simply a hidden `<div>` placeholder into which Nosto injects recommendations or personalises the content between the tags.
 *
 * We recommend adding as many placements across your views as needed as these are hidden and only populated when a corresponding campaign (targeting that placement) is configured.
 *
 * @example
 * ```
 * <NostoPlacement id="frontpage-nosto-1" />
 * ```
 *
 * @group Components
 */
export declare function NostoPlacement({ id, pageType, children }: NostoPlacementProps): JSX.Element;

/**
 * @group Components
 */
export declare type NostoPlacementProps = {
    id: string;
    pageType?: string;
    children?: React.ReactNode;
};

/**
 * The NostoProduct component must be used to personalise the product page.
 * The component requires that you provide it the identifier of the current product being viewed.
 *
 * By default, your account, when created, has three product-page placements named `productpage-nosto-1`, `productpage-nosto-2` and `productpage-nosto-3`.
 * You may omit these and use any identifier you need.
 * The identifiers used here are simply provided to illustrate the example.
 *
 * The `<NostoProduct \>` component needs to be added after the placements.
 * Content and recommendations will be rendered through this component.
 * Pass in the product ID via the product prop to pass this information back to Nosto.
 *
 * @example
 * ```
 * <div className="product-page">
 *   <NostoPlacement id="productpage-nosto-1" />
 *   <NostoPlacement id="productpage-nosto-2" />
 *   <NostoPlacement id="productpage-nosto-3" />
 *   <NostoProduct product={product.id} />
 * </div>
 * ```
 *
 * @group Components
 */
export declare function NostoProduct(props: NostoProductProps): null;

/**
 * @group Hooks
 */
export declare type NostoProductProps = {
    product: string;
    reference?: string;
    tagging?: Product;
    placements?: string[];
};

/**
 * This widget is what we call the Nosto root widget, which is responsible for adding the actual Nosto script and the JS API stub.
 * This widget wraps all other React Nosto widgets.
 *
 * ```
 * <NostoProvider account="your-nosto-account-id" recommendationComponent={<NostoSlot />}>
 *   <App />
 * </NostoProvider>
 * ```
 *
 * **Note:** the component also accepts a prop to configure the host `host="connect.nosto.com"`.
 * In advanced use-cases, the need to configure the host may surface.
 *
 * In order to implement client-side rendering, the requires a designated component to render the recommendations provided by Nosto.
 * This component should be capable of processing the JSON response received from our backend.
 * Notice the `recommendationComponent` prop passed to `<NostoProvider>` above.
 *
 * Learn more [here](https://github.com/Nosto/shopify-hydrogen/blob/main/README.md#client-side-rendering-for-recommendations) and see a [live example](https://github.com/Nosto/shopify-hydrogen-demo) on our demo store.
 *
 * @group Components
 */
export declare function NostoProvider(props: NostoProviderProps): JSX.Element;

/**
 * @group Components
 */
export declare interface NostoProviderProps {
    /**
     * Indicates merchant id
     */
    account: string;
    /**
     * Indicates currency
     */
    currentVariation?: string;
    /**
     * Indicates an url of a server
     */
    host?: string;
    /**
     * children
     */
    children: ReactNode | ReactNode[];
    /**
     * Indicates if merchant uses multiple currencies
     */
    multiCurrency?: boolean;
    /**
     * Recommendation component which holds nostoRecommendation object
     */
    recommendationComponent?: RecommendationComponent;
    /**
     * Recommendation render mode. See {@link https://nosto.github.io/nosto-js/types/client.RenderMode.html}
     */
    renderMode?: RenderMode;
    /**
     * Enables Shopify markets with language and market id
     */
    shopifyMarkets?: {
        language: string;
        marketId: string | number;
    };
    /**
     * Load nosto script (should be false if loading the script outside of nosto-react)
     */
    loadScript?: boolean;
    /**
     * Custom script loader
     */
    scriptLoader?: (scriptSrc: string, options?: ScriptLoadOptions) => Promise<void>;
}

/**
 * You can personalise your search pages by using the NostoSearch component.
 * The component requires that you provide it the current search term.
 *
 * By default, your account, when created, has two search-page placements named `searchpage-nosto-1` and `searchpage-nosto-2`.
 * You may omit these and use any identifier you need. The identifiers used here are simply provided to illustrate the example.
 *
 * @example
 * ```
 * <div className="search-page">
 *   <NostoPlacement id="searchpage-nosto-1" />
 *   <NostoPlacement id="searchpage-nosto-2" />
 *   <NostoSearch query={"black shoes"} />
 * </div>
 * ```
 *
 * **Note:** Do not encode the search term in any way.
 * It should be provided an unencoded string.
 * A query for `black shoes` must be provided as-is and not as `black+shoes`.
 * Doing so will lead to invalid results.
 *
 * @group Components
 */
export declare function NostoSearch(props: NostoSearchProps): null;

/**
 * @group Components
 */
export declare type NostoSearchProps = {
    query: string;
    placements?: string[];
};

/**
 * Nosto React requires that you pass it the details of current cart contents and the details of the currently logged-in customer, if any, on every route change.
 * This makes it easier to add attribution.
 *
 * The `NostoSession` component makes it very easy to keep the session up to date so long as the cart and the customer are provided.
 *
 * The cart prop requires a value that adheres to the type `Cart`, while the customer prop requires a value that adheres to the type `Customer`.
 *
 * @group Components
 */
export declare function NostoSession(props?: NostoSessionProps): null;

/**
 * @group Hooks
 */
export declare type NostoSessionProps = {
    cart?: Cart | ToCamelCase<Cart>;
    customer?: Customer | ToCamelCase<Customer>;
};

export { Order }

export { Product }

/**
 * @group Types
 */
export declare interface Recommendation {
    result_id: string;
    products: PushedProduct[];
    result_type: string;
    title: string;
    div_id: string;
    source_product_ids: string[];
    params: unknown;
}

export declare type RecommendationComponent = ReactElement<{
    nostoRecommendation: Recommendation;
}>;

export { RenderMode }

/**
 * @group Types
 */
export declare type ScriptLoadOptions = {
    /**
     * Indicates the position of the script, default is "body"
     */
    position?: "head" | "body";
    /**
     * Indicates the attributes of the script element
     */
    attributes?: Record<string, string>;
};

export declare type SnakeToCamelCase<S extends string> = S extends `${infer T}_${infer U}` ? `${T}${Capitalize<SnakeToCamelCase<U>>}` : S;

export declare type ToCamelCase<T> = T extends (infer U)[] ? ToCamelCase<U>[] : T extends Date ? T : T extends object ? {
    [K in keyof T as SnakeToCamelCase<K & string>]: ToCamelCase<T[K]>;
} : T;

/**
 * You can personalise your cart and checkout pages by using the `useNosto404` hook.
 *
 * @group Hooks
 */
export declare function useNosto404(props?: Nosto404Props): void;

/**
 * You can personalise your category and collection pages by using the useNostoCategory hook.
 *
 * @group Hooks
 */
export declare function useNostoCategory({ category, placements }: NostoCategoryProps): void;

/**
 * You can personalise your cart and checkout pages by using the useNostoCheckout hook.
 *
 * @group Hooks
 */
export declare function useNostoCheckout(props?: NostoCheckoutProps): void;

/**
 * A hook that allows you to access the NostoContext and retrieve Nosto-related data from it in React components.
 *
 * @group Essential Functions
 */
export declare function useNostoContext(): NostoContextType;

/**
 * You can personalise your home page by using the useNostoHome hook.
 *
 * @group Hooks
 */
export declare function useNostoHome(props?: NostoHomeProps): void;

/**
 * You can personalise your order-confirmation/thank-you page by using the `useNostoOrder` hook.
 *
 * @group Hooks
 */
export declare function useNostoOrder({ order, placements }: NostoOrderProps): void;

/**
 * You can personalise your miscellaneous pages by using the useNostoOther hook.
 *
 * @group Hooks
 */
export declare function useNostoOther(props?: NostoOtherProps): void;

/**
 * You can personalise your product pages by using the useNostoProduct hook.
 *
 * @group Hooks
 */
export declare function useNostoProduct({ product, tagging, placements, reference }: NostoProductProps): void;

/**
 * You can personalise your search pages by using the useNostoSearch hook.
 *
 * @group Hooks
 */
export declare function useNostoSearch({ query, placements }: NostoSearchProps): void;

/**
 * Nosto React requires that you pass it the details of current cart contents and the details of the currently logged-in customer, if any, on every route change.
 *
 * @group Hooks
 */
export declare function useNostoSession({ cart, customer }?: NostoSessionProps): void;

export { }
