import { DocumentDecoration, Elysia } from 'elysia';
import { Context } from 'elysia/context';
import { InlineConfig } from 'vite';

interface StaticOptions<Prefix extends string> {
    /**
     * @default "public"
     *
     * Asset path to expose as public path
     */
    assets?: string;
    /**
     * @default '/public'
     *
     * Path prefix to create virtual mount path for the static directory
     */
    prefix?: Prefix;
    /**
     * @default 1024
     *
     * If total files exceed this number,
     * file will be handled via wildcard instead of static route
     * to reduce memory usage
     */
    staticLimit?: number;
    /**
     * @default false unless `NODE_ENV` is 'production'
     *
     * Should file always be served statically
     */
    alwaysStatic?: boolean;
    /**
     * @default [] `Array<string | RegExp>`
     *
     * Array of file to ignore publication.
     * If one of the patters is matched,
     * file will not be exposed.
     */
    ignorePatterns?: Array<string | RegExp>;
    /**
     * Indicate if file extension is required
     *
     * Only works if `alwaysStatic` is set to true
     *
     * @default true
     */
    extension?: boolean;
    /**
     *
     * When url needs to be decoded
     *
     * Only works if `alwaysStatic` is set to false
     */
    /**
     * Set headers
     */
    headers?: Record<string, string> | undefined;
    /**
     * @default true
     *
     * If set to false, browser caching will be disabled
     *
     * On Bun, if set to false, performance will be significantly improved
     * as it can be inline as a static resource
     */
    etag?: boolean;
    /**
     * @default public
     *
     * directive for Cache-Control header
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#directives
     */
    directive?: 'public' | 'private' | 'must-revalidate' | 'no-cache' | 'no-store' | 'no-transform' | 'proxy-revalidate' | 'immutable';
    /**
     * @default 86400
     *
     * Specifies the maximum amount of time in seconds, a resource will be considered fresh.
     * This freshness lifetime is calculated relative to the time of the request.
     * This setting helps control browser caching behavior.
     * A `maxAge` of 0 will prevent caching, requiring requests to validate with the server before use.
     */
    maxAge?: number | null;
    /**
     *
     */
    /**
     * @default true
     *
     * Enable serving of index.html as default / route
     */
    indexHTML?: boolean;
    /**
     * @default false
     *
     * Enable bundling of HTML files (Bun only).
     * When true, HTML imports using Bun’s bundler, JavaScript transpiler and CSS parser. [See more](https://bun.com/docs/bundler/fullstack)
     * When false, HTML files are served directly from disk.
     */
    bunFullstack?: boolean;
    /**
     * decodeURI
     *
     * @default false
     */
    decodeURI?: boolean;
    detail?: DocumentDecoration | ((path: string) => DocumentDecoration);
    /**
     * silent
     *
     * @default false
     *
     * If set to true, suppresses all logs and warnings from the static plugin
     */
    silent?: boolean;
}

declare function staticPlugin<const Prefix extends string = '/prefix'>({ assets, prefix, staticLimit, alwaysStatic, ignorePatterns, headers: initialHeaders, maxAge, directive, etag: useETag, extension, indexHTML, detail, bunFullstack, decodeURI, silent }?: StaticOptions<Prefix>): Promise<Elysia>;

type GetLoadContext<T> = (context: Context) => T | Promise<T>;
interface PluginOptions<T> {
    /**
     * in `development` mode it starts `vite` and in `production` it just served like static.
     *
     * @default process.env.NODE_ENV || "development"
     */
    mode?: "development" | "production";
    /**
     * The base path for the Remix app.
     * This should match the `basename` in your `vite` config.
     *
     * @default "/"
     */
    basename?: string;
    /**
     * The directory where the Remix app is built.
     * This should match the `buildDirectory` directory in your `vite` config.
     *
     * @default "build"
     */
    buildDirectory?: string;
    /**
     * The Remix server output filename.
     * This should match the `serverBuildFile` filename in your `vite` config.
     *
     * @default "index.js"
     */
    serverBuildFile?: string;
    /**
     * Configure `vite` server in `development` mode
     */
    vite?: InlineConfig;
    /**
     * A function that returns the value to use as `context` in route `loader` and
     * `action` functions.
     *
     * You can use declaration merging for type it correctly https://www.typescriptlang.org/docs/handbook/declaration-merging.html
     */
    getLoadContext?: GetLoadContext<T>;
    /**
     * Options for production mode (serving static assets and performs SSR)
     */
    production?: {
        assets?: StaticPluginOptions | false;
        /**
         * A function to change the response of static assets. (For example, for `cache-control` headers)
         */
        /** @deprecated (removed) in favour of `assets` option */
        wrapStaticResponse?: never;
    };
}
type StaticPluginOptions = Parameters<typeof staticPlugin>[0];

export type { PluginOptions as P };
