import * as _nuxt_schema from '@nuxt/schema';
import { Nuxt, HookResult } from '@nuxt/schema';
import { createAdminApiClient, AdminApiClient } from '@shopify/admin-api-client';
import { createStorefrontApiClient, StorefrontApiClient } from '@shopify/storefront-api-client';
import { ConsolaOptions } from 'consola';
import { ResponseErrors } from '@shopify/graphql-client';

type StorefrontOptions = Parameters<typeof createStorefrontApiClient>[0]
type AdminOptions = Parameters<typeof createAdminApiClient>[0]

// The supported client types
declare enum ShopifyClientType {
    Storefront = 'storefront',
    Admin = 'admin',
}

// custom options for each client
// exposed via module options
type ShopifyClientCustomConfig = {
    skipCodegen?: boolean
    sandbox?: boolean // defaults to true
    documents?: string[]
}

type ShopifyStorefrontConfig = StorefrontOptions & ShopifyClientCustomConfig
type ShopifyAdminConfig = AdminOptions & ShopifyClientCustomConfig

// Fully resolved shopify config
type ShopifyConfig<S = ShopifyStorefrontConfig, A = ShopifyAdminConfig> = {
    name: string
    logger?: Partial<ConsolaOptions>
    autoImports?: {
        graphql?: boolean
        storefront?: boolean
        admin?: boolean
    }
    errors?: {
        throw?: boolean
    }
    clients: {
        [ShopifyClientType.Storefront]?: S
        [ShopifyClientType.Admin]?: A
    }
}

// Optional public config for client side usage
type PublicShopifyConfig<S = ShopifyStorefrontConfig> = {
    logger?: Partial<ConsolaOptions>
    errors?: {
        throw?: boolean
    }
    clients: {
        [ShopifyClientType.Storefront]?: Omit<S, 'privateAccessToken' | 'skipCodegen' | 'sandbox' | 'documents'>
    }
}

type ModuleOptions = ShopifyConfig<
    Omit<ShopifyStorefrontConfig, 'storeDomain' | 'logger' | 'customFetchApi'>,
    Omit<ShopifyAdminConfig, 'storeDomain' | 'logger' | 'customFetchApi'>
>

type ShopifyConfigHookParams = {
    nuxt: Nuxt
    config: ShopifyConfig
}

type ShopifyClientOptionHookParams<T = StorefrontOptions | AdminOptions> = {
    options: T
}

type ShopifyClientHookParams<T = StorefrontApiClient | AdminApiClient> = {
    client: T
}

type ShopifyErrorHookParams = {
    errors: ResponseErrors
}

type ShopifyTemplateHookParams = {
    nuxt: Nuxt
    config: Record<string, unknown>
}

type SandboxConfig = {
    url: string
    headers: Record<string, string>
}

declare module '@nuxt/schema' {
    interface RuntimeConfig {
        _shopify?: ShopifyConfig
        _sandbox?: Record<string, SandboxConfig>
    }

    interface PublicRuntimeConfig {
        _shopify?: PublicShopifyConfig
    }

    interface NuxtHooks {
        /**
         * Called before the config is persisted into the runtime config
         */
        'shopify:config': ({ nuxt, config }: ShopifyConfigHookParams) => HookResult

        /**
         * Called before the storefront introspection schema is generated
         */
        'storefront:generate:introspection': ({ nuxt, config }: ShopifyTemplateHookParams) => HookResult

        /**
         * Called before the storefront types are generated
         */
        'storefront:generate:types': ({ nuxt, config }: ShopifyTemplateHookParams) => HookResult

        /**
         * Called before the storefront operations are generated
         */
        'storefront:generate:operations': ({ nuxt, config }: ShopifyTemplateHookParams) => HookResult

        /**
         * Called before the admin introspection schema is generated
         */
        'admin:generate:introspection': ({ nuxt, config }: ShopifyTemplateHookParams) => HookResult

        /**
         * Called before the admin types are generated
         */
        'admin:generate:types': ({ nuxt, config }: ShopifyTemplateHookParams) => HookResult

        /**
         * Called before the admin operations are generated
         */
        'admin:generate:operations': ({ nuxt, config }: ShopifyTemplateHookParams) => HookResult
    }
}

declare module '#app' {
    interface RuntimeNuxtHooks {
        /**
         * Called before the storefront client is created within nuxt
         */
        'storefront:client:configure': ({ options }: ShopifyClientOptionHookParams<Omit<StorefrontOptions, 'privateAccessToken'>>) => HookResult

        /**
         * Called after the storefront client is created within nuxt
         */
        'storefront:client:create': ({ client }: ShopifyClientHookParams<StorefrontApiClient>) => HookResult

        /**
         * Called when the storefront client throws an error within nuxt
         */
        'storefront:client:errors': ({ errors }: ShopifyErrorHookParams) => HookResult
    }
}

declare module 'nitropack' {
    interface NitroRuntimeHooks {
        /**
         * Called before the storefront client is created within nitro
         */
        'storefront:client:configure': ({ options }: ShopifyClientOptionHookParams<StorefrontOptions>) => HookResult

        /**
         * Called after the storefront client is created within nitro
         */
        'storefront:client:create': ({ client }: ShopifyClientHookParams<StorefrontApiClient>) => HookResult

        /**
         * Called when the storefront client throws an error within nitro
         */
        'storefront:client:errors': ({ errors }: ShopifyErrorHookParams) => HookResult

        /**
         * Called after the admin client is created within nitro
         */
        'admin:client:configure': ({ options }: ShopifyClientOptionHookParams<AdminOptions>) => HookResult

        /**
         * Called when the admin client is created within nitro
         */
        'admin:client:create': ({ client }: ShopifyClientHookParams<AdminApiClient>) => HookResult

        /**
         * Called when the admin client throws an error within nitro
         */
        'admin:client:errors': ({ errors }: ShopifyErrorHookParams) => HookResult
    }
}

declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;

export { _default as default };
