import type { BetterAuthPlugin, LiteralString } from "@better-auth/core";
import { createAuthEndpoint } from "@better-auth/core/api";
import { APIError } from "../../api";
import { HIDE_METADATA } from "../../utils";
import { PACKAGE_VERSION } from "../../version";
import { generator } from "./generator";
import { logo } from "./logo";

declare module "@better-auth/core" {
	interface BetterAuthPluginRegistry<AuthOptions, Options> {
		"open-api": {
			creator: typeof openAPI;
		};
	}
}

export type { FieldSchema, OpenAPIModelSchema, Path } from "./generator";

type ScalarTheme =
	| "alternate"
	| "default"
	| "moon"
	| "purple"
	| "solarized"
	| "bluePlanet"
	| "saturn"
	| "kepler"
	| "mars"
	| "deepSpace"
	| "laserwave"
	| "none";

const getHTML = (
	apiReference: Record<string, any>,
	theme?: ScalarTheme | undefined,
	nonce?: string | undefined,
) => {
	const nonceAttr = nonce ? `nonce="${nonce}"` : "";
	return `<!doctype html>
<html>
  <head>
    <title>Scalar API Reference</title>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <script
      id="api-reference"
      type="application/json">
    ${JSON.stringify(apiReference)}
    </script>
	 <script ${nonceAttr}>
      var configuration = {
	  	favicon: "data:image/svg+xml;utf8,${encodeURIComponent(logo)}",
	   	theme: "${theme || "default"}",
        metaData: {
			title: "Better Auth API",
			description: "API Reference for your Better Auth Instance",
		}
      }

      document.getElementById('api-reference').dataset.configuration =
        JSON.stringify(configuration)
    </script>
	  <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference" ${nonceAttr}></script>
  </body>
</html>`;
};

export interface OpenAPIOptions {
	/**
	 * The path to the OpenAPI reference page
	 *
	 * keep in mind that this path will be appended to the base URL `/api/auth` path
	 * by default, so if you set this to `/reference`, the full path will be `/api/auth/reference`
	 *
	 * @default "/reference"
	 */
	path?: LiteralString | undefined;
	/**
	 * Disable the default reference page that is generated by Scalar
	 *
	 * @default false
	 */
	disableDefaultReference?: boolean | undefined;
	/**
	 * Theme of the OpenAPI reference page.
	 *
	 * @default "default"
	 */
	theme?: ScalarTheme | undefined;
	/**
	 * A 'nonce' string to be attached to inline scripts
	 * for Content Security Policy (CSP) compliance.
	 * @default undefined
	 */
	nonce?: string | undefined;
}

export const openAPI = <O extends OpenAPIOptions>(options?: O | undefined) => {
	const path = options?.path ?? "/reference";
	return {
		id: "open-api",
		version: PACKAGE_VERSION,
		endpoints: {
			generateOpenAPISchema: createAuthEndpoint(
				"/open-api/generate-schema",
				{
					method: "GET",
				},
				async (ctx) => {
					const schema = await generator(ctx.context, ctx.context.options);
					return ctx.json(schema);
				},
			),
			openAPIReference: createAuthEndpoint(
				path,
				{
					method: "GET",
					metadata: HIDE_METADATA,
				},
				async (ctx) => {
					if (options?.disableDefaultReference) {
						throw new APIError("NOT_FOUND");
					}
					const schema = await generator(ctx.context, ctx.context.options);
					return new Response(getHTML(schema, options?.theme, options?.nonce), {
						headers: {
							"Content-Type": "text/html",
						},
					});
				},
			),
		},
		options: options as NoInfer<O>,
	} satisfies BetterAuthPlugin;
};

export type * from "./generator";
