import type {
	ExtensionUIContext,
	ExtensionWidgetOptions,
} from "../../../core/extensions/index.js";
import { appKey } from "../components/keybinding-hints.js";
import {
	getAvailableThemesWithPaths,
	getThemeByName,
	setTheme,
	setThemeInstance,
	Theme,
	theme,
} from "../theme/theme.js";

type ExtensionNotifyType = "info" | "warning" | "error" | "success";

type ExtensionWidgetContent =
	| string[]
	| ((...args: any[]) => unknown)
	| undefined;

function notifyHost(
	host: any,
	message: string,
	type: ExtensionNotifyType = "info",
): void {
	if (typeof host.showExtensionNotify === "function") {
		host.showExtensionNotify(message, type);
		return;
	}

	if (type === "error" && typeof host.showError === "function") {
		host.showError(message);
		return;
	}
	if (type === "warning" && typeof host.showWarning === "function") {
		host.showWarning(message);
		return;
	}
	if (typeof host.showStatus === "function") {
		host.showStatus(message, { append: type === "success" });
		return;
	}
	host.ui?.requestRender?.();
}

/**
 * Resolve the host's widget setter capability once, safely.
 *
 * Purpose: avoid probing `host.setExtensionWidget` on every `setWidget` call.
 * Embedded/stale hosts may expose incompatible getters/shims that throw on
 * access; we catch that at context creation time and degrade to a no-op.
 *
 * Returns the bound setter if available and callable, otherwise `undefined`.
 */
function resolveWidgetSetter(
	host: any,
): ((key: string, content: unknown, options?: unknown) => void) | undefined {
	try {
		const fn = host.setExtensionWidget;
		return typeof fn === "function" ? fn.bind(host) : undefined;
	} catch {
		return undefined;
	}
}

/**
 * Build a `setWidget` implementation for the given host.
 *
 * The returned function never throws. If the host does not support extension
 * widgets, it degrades to a no-op. If the host setter throws at call time,
 * the error is caught and silently ignored (widgets are optional UI sugar).
 */
function createWidgetSetter(
	host: any,
): (
	key: string,
	content: ExtensionWidgetContent,
	options?: ExtensionWidgetOptions,
) => void {
	const setter = resolveWidgetSetter(host);
	if (!setter) {
		return (_key, _content, _options) => {
			// Host does not support extension widgets.
		};
	}
	return (key, content, options) => {
		try {
			setter(key, content, options);
		} catch {
			// Widget render failed. Optional UI sugar; degrade silently.
		}
	};
}

export function createExtensionUIContext(host: any): ExtensionUIContext {
	const setWidget = createWidgetSetter(host);
	return {
		select: (title, options, opts) => {
			if (typeof host.showExtensionSelector !== "function") {
				return Promise.resolve(undefined);
			}
			return host.showExtensionSelector(title, options, opts);
		},
		confirm: (title, message, opts) => {
			if (typeof host.showExtensionConfirm !== "function") {
				return Promise.resolve(false);
			}
			return host.showExtensionConfirm(title, message, opts);
		},
		input: (title, placeholder, opts) => {
			if (typeof host.showExtensionInput !== "function") {
				return Promise.resolve(undefined);
			}
			return host.showExtensionInput(title, placeholder, opts);
		},
		notify: (message, type) => notifyHost(host, message, type),
		onTerminalInput: (handler) =>
			host.addExtensionTerminalInputListener(handler),
		setStatus: (key, text) => host.setExtensionStatus(key, text),
		setWorkingMessage: (message) => {
			if (host.loadingAnimation) {
				if (message) {
					host.loadingAnimation.setMessage(message);
				} else {
					host.loadingAnimation.setMessage(
						`${host.defaultWorkingMessage} (${appKey(host.keybindings, "interrupt")} to interrupt)`,
					);
				}
			} else {
				host.pendingWorkingMessage = message;
			}
		},
		setWorkingVisible: (visible) => {
			if (host.loadingAnimation) {
				host.loadingAnimation.setVisible(visible);
			}
		},
		setWidget,
		setFooter: (factory) => host.setExtensionFooter(factory),
		setHeader: (factory) => host.setExtensionHeader(factory),
		setTitle: (title) => host.ui.terminal.setTitle(title),
		custom: (factory, options) => host.showExtensionCustom(factory, options),
		pasteToEditor: (text) =>
			host.editor.handleInput(`\x1b[200~${text}\x1b[201~`),
		setEditorText: (text) => host.editor.setText(text),
		getEditorText: () => host.editor.getText(),
		editor: (title, prefill) => host.showExtensionEditor(title, prefill),
		setEditorComponent: (factory) => host.setCustomEditorComponent(factory),
		get theme() {
			return theme;
		},
		getAllThemes: () => getAvailableThemesWithPaths(),
		getTheme: (name) => getThemeByName(name),
		setTheme: (themeOrName) => {
			if (themeOrName instanceof Theme) {
				setThemeInstance(themeOrName);
				host.ui.requestRender();
				return { success: true };
			}
			const result = setTheme(themeOrName, true);
			if (result.success) {
				if (host.settingsManager.getTheme() !== themeOrName) {
					host.settingsManager.setTheme(themeOrName);
				}
				host.ui.requestRender();
			}
			return result;
		},
		getToolsExpanded: () => host.toolOutputExpanded,
		setToolsExpanded: (expanded) => host.setToolsExpanded(expanded),
	};
}
