import { normalizePath } from 'vite';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { debug } from './debug.js';
import { defaultInspectorOptions, parseEnvironmentOptions } from './options.js';
import { cleanUrl } from './utils.js';

function getInspectorPath() {
	const pluginPath = normalizePath(path.dirname(fileURLToPath(import.meta.url)));
	return pluginPath.replace(
		/\/vite-plugin-svelte-inspector\/src$/,
		'/vite-plugin-svelte-inspector/src/runtime/'
	);
}

/**
 * @param {Partial<import('./public.d.ts').Options>} [options]
 * @returns {import('vite').Plugin}
 */
export function svelteInspector(options) {
	const inspectorPath = getInspectorPath();
	debug(`svelte inspector path: ${inspectorPath}`);

	/** @type {import('vite').ResolvedConfig} */
	let viteConfig;
	/** @type {import('./public.d.ts').Options} */
	let inspectorOptions;
	let disabled = false;

	return {
		name: 'vite-plugin-svelte-inspector',
		apply: 'serve',
		enforce: 'pre',

		configResolved(config) {
			viteConfig = config;

			const environmentOptions = parseEnvironmentOptions(config);
			if (environmentOptions === false) {
				debug('environment options set to false, inspector disabled');
				disabled = true;
				return;
			}

			// Handle config from svelte.config.js through vite-plugin-svelte
			const vps = config.plugins.find((p) => p.name === 'vite-plugin-svelte');
			const configFileOptions = vps?.api?.options?.inspector;

			// vite-plugin-svelte can only pass options through it's `api` instead of `options`.
			// that means this plugin could be created but should be disabled, so we check this case here.
			if (vps && !options && !configFileOptions && !environmentOptions) {
				debug("vite-plugin-svelte didn't pass options, inspector disabled");
				disabled = true;
				return;
			}

			if (environmentOptions === true) {
				inspectorOptions = defaultInspectorOptions;
			} else {
				inspectorOptions = {
					...defaultInspectorOptions,
					...configFileOptions,
					...options,
					...(environmentOptions || {})
				};
			}

			inspectorOptions.__internal = {
				base: config.base?.replace(/\/$/, '') || ''
			};
		},

		async resolveId(importee, _, options) {
			if (options?.ssr || disabled) {
				return;
			}
			if (importee.startsWith('virtual:svelte-inspector-options')) {
				return importee;
			} else if (importee.startsWith('virtual:svelte-inspector-path:')) {
				return importee.replace('virtual:svelte-inspector-path:', inspectorPath);
			}
		},

		async load(id, options) {
			if (options?.ssr || disabled) {
				return;
			}
			if (id === 'virtual:svelte-inspector-options') {
				return `export default ${JSON.stringify(inspectorOptions ?? {})}`;
			} else if (id.startsWith(inspectorPath)) {
				// read file ourselves to avoid getting shut out by vites fs.allow check
				const file = cleanUrl(id);
				if (fs.existsSync(id)) {
					return await fs.promises.readFile(file, 'utf-8');
				} else {
					viteConfig.logger.error(
						`[vite-plugin-svelte-inspector] failed to find svelte-inspector: ${id}`
					);
				}
			}
		},

		transform(code, id, options) {
			if (options?.ssr || disabled) {
				return;
			}
			if (id.includes('vite/dist/client/client.mjs')) {
				return { code: `${code}\nimport('virtual:svelte-inspector-path:load-inspector.js')` };
			}
		}
	};
}