/**
 * FlowDrop Shared Library for Drupal
 *
 * This module provides a unified export of FlowDrop functionality for use
 * in Drupal Single Directory Components (SDC). It combines all FlowDrop
 * capabilities - workflow editor, schema forms, playground, and display
 * components - into a single shared library.
 *
 * Heavy optional features (CodeMirror code editors, EasyMDE markdown editor)
 * are lazy-loaded via dynamic import() and only fetched when their
 * registration functions are called.
 *
 * @example
 * // The library exposes window.FlowDrop with all exports
 * const { mountFlowDropApp, mountSchemaForm, mountPlayground } = window.FlowDrop;
 *
 * // Mount workflow editor
 * const editor = await mountFlowDropApp(container, { workflow, endpointConfig });
 *
 * // Mount schema form
 * const form = mountSchemaForm(container, { schema, values, onChange });
 *
 * // Mount playground
 * const playground = await mountPlayground(container, { workflowId, endpointConfig });
 */

/**
 * Library version — matches the Drupal module release.
 * Consumers can check `window.FlowDrop.VERSION` to verify API compatibility.
 */
export const VERSION = "1.0.0-alpha4";

/**
 * Import base styles from the FlowDrop package
 */
import "@d34dman/flowdrop/styles/base.css";
import "@d34dman/flowdrop/styles/toast.css";

import type { Component } from "svelte";
import type { MountedFlowDropApp, FlowDropMountOptions } from "@d34dman/flowdrop/core";
import type { Workflow, NodeMetadata, PortConfig, CategoryDefinition } from "@d34dman/flowdrop/core";
import type { EndpointConfig } from "@d34dman/flowdrop/core";
import type { MountedPlayground, PlaygroundMountOptions } from "@d34dman/flowdrop/playground";

/**
 * Mount options for the WorkflowEditor component (without navbar).
 * A subset of FlowDropMountOptions focused on editor-only configuration.
 */
export interface WorkflowEditorMountOptions {
	/** Initial workflow to load */
	workflow?: Workflow;
	/** Available node types */
	nodes?: NodeMetadata[];
	/** API endpoint configuration */
	endpointConfig?: EndpointConfig;
	/** Port configuration for connections */
	portConfig?: PortConfig;
	/** Category definitions for node categories */
	categories?: CategoryDefinition[];
}

// ============================================================================
// Re-export from Sub-modules
// ============================================================================
// We import from specific sub-modules instead of the catch-all main entry
// to avoid pulling in FormFieldFull (which statically imports CodeMirror).
// This enables CodeMirror to be lazy-loaded as a separate chunk.

/** Core types and utilities (no heavy dependencies) */
export * from "@d34dman/flowdrop/core";

// ============================================================================
// Workflow Editor Exports — Lazy-loaded
// ============================================================================
// The editor module includes @xyflow/svelte and all node components (~350 KB).
// It's lazy-loaded so pages that only need SchemaForm or Playground don't
// pay the cost of editor code.

/** Cached module reference for @d34dman/flowdrop/editor */
let _editorModule: typeof import("@d34dman/flowdrop/editor") | null = null;

/** Load the editor module on demand */
async function loadEditorModule() {
	if (!_editorModule) {
		_editorModule = await import("@d34dman/flowdrop/editor");
	}
	return _editorModule;
}

/**
 * Mount the full FlowDrop app with navbar (lazy-loads editor chunk)
 */
export async function mountFlowDropApp(
	container: HTMLElement,
	options: FlowDropMountOptions
): Promise<MountedFlowDropApp> {
	const mod = await loadEditorModule();
	return mod.mountFlowDropApp(container, options);
}

/**
 * Mount the workflow editor component only (lazy-loads editor chunk)
 */
export async function mountWorkflowEditor(
	container: HTMLElement,
	options: WorkflowEditorMountOptions
): Promise<MountedFlowDropApp> {
	const mod = await loadEditorModule();
	return mod.mountWorkflowEditor(container, options);
}

/**
 * Unmount a FlowDrop app instance
 */
export async function unmountFlowDropApp(app: MountedFlowDropApp): Promise<void> {
	const mod = await loadEditorModule();
	mod.unmountFlowDropApp(app);
}

/**
 * Get the full editor module for advanced use (stores, helpers, registry, etc.)
 * Lazy-loads the editor chunk if not already loaded.
 */
export async function getEditorModule() {
	return loadEditorModule();
}

/** Display components (includes marked for markdown rendering) */
export * from "@d34dman/flowdrop/display";

/**
 * Form components — safe to use `export *` because formFieldLightPlugin
 * redirects FormField.svelte → FormFieldLight.svelte at build time,
 * keeping CodeMirror out of the main chunk.
 * New exports added to @d34dman/flowdrop/form are picked up automatically.
 */
export * from "@d34dman/flowdrop/form";

/**
 * Theme and settings — imported via aliased internal paths to bypass the
 * package.json exports restriction. The "flowdrop-internal" alias is
 * configured in vite.config.ts.
 * Using `export *` so new exports are picked up automatically on upgrade.
 */
export { default as ThemeToggle } from "flowdrop-internal/components/ThemeToggle.svelte";
export { default as SettingsPanel } from "flowdrop-internal/components/SettingsPanel.svelte";
export { default as SettingsModal } from "flowdrop-internal/components/SettingsModal.svelte";
export * from "flowdrop-internal/stores/settingsStore.svelte.js";
export * from "flowdrop-internal/services/settingsService.js";

// ============================================================================
// Form Code Editor Exports (CodeMirror-based editors) — Lazy-loaded
// ============================================================================

/** Cached module reference for @d34dman/flowdrop/form/code */
let _codeModule: typeof import("@d34dman/flowdrop/form/code") | null = null;

/** Load the code editor module on demand */
async function loadCodeModule() {
	if (!_codeModule) {
		_codeModule = await import("@d34dman/flowdrop/form/code");
	}
	return _codeModule;
}

/**
 * Get the FormCodeEditor component (lazy-loaded)
 */
export async function getFormCodeEditor() {
	const mod = await loadCodeModule();
	return mod.FormCodeEditor;
}

/**
 * Get the FormTemplateEditor component (lazy-loaded)
 */
export async function getFormTemplateEditor() {
	const mod = await loadCodeModule();
	return mod.FormTemplateEditor;
}

/**
 * Matcher for code/JSON editor fields.
 * Delegates to the real matcher once the module is loaded;
 * returns false if the module hasn't been loaded yet.
 */
export function codeEditorFieldMatcher(schema: { format?: string; type?: string }): boolean {
	return _codeModule?.codeEditorFieldMatcher(schema) ?? false;
}

/**
 * Matcher for template editor fields.
 * Delegates to the real matcher once the module is loaded;
 * returns false if the module hasn't been loaded yet.
 */
export function templateEditorFieldMatcher(schema: { format?: string; type?: string }): boolean {
	return _codeModule?.templateEditorFieldMatcher(schema) ?? false;
}

/**
 * Register the code/JSON editor field component (lazy-loads CodeMirror)
 */
export async function registerCodeEditorField(priority?: number): Promise<void> {
	const mod = await loadCodeModule();
	mod.registerCodeEditorField(priority);
}

/**
 * Register the template editor field component (lazy-loads CodeMirror)
 */
export async function registerTemplateEditorField(priority?: number): Promise<void> {
	const mod = await loadCodeModule();
	mod.registerTemplateEditorField(priority);
}

/**
 * Register all code-related editor fields (lazy-loads CodeMirror)
 */
export async function registerAllCodeEditors(priority?: number): Promise<void> {
	const mod = await loadCodeModule();
	mod.registerAllCodeEditors(priority);
}

/**
 * Register code editor field using an already-imported component (lazy-loads module)
 */
export async function registerCodeEditorFieldWithComponent(component: Component, priority?: number): Promise<void> {
	const mod = await loadCodeModule();
	mod.registerCodeEditorFieldWithComponent(component, priority);
}

/**
 * Check if code editor field is registered.
 * Returns false if the module hasn't been loaded yet.
 */
export function isCodeEditorRegistered(): boolean {
	return _codeModule?.isCodeEditorRegistered() ?? false;
}

/**
 * Check if template editor field is registered.
 * Returns false if the module hasn't been loaded yet.
 */
export function isTemplateEditorRegistered(): boolean {
	return _codeModule?.isTemplateEditorRegistered() ?? false;
}

// ============================================================================
// Form Markdown Editor Exports (EasyMDE-based editor) — Lazy-loaded
// ============================================================================

/** Cached module reference for @d34dman/flowdrop/form/markdown */
let _markdownModule: typeof import("@d34dman/flowdrop/form/markdown") | null = null;

/** Load the markdown editor module on demand */
async function loadMarkdownModule() {
	if (!_markdownModule) {
		_markdownModule = await import("@d34dman/flowdrop/form/markdown");
	}
	return _markdownModule;
}

/**
 * Get the FormMarkdownEditor component (lazy-loaded)
 */
export async function getFormMarkdownEditor() {
	const mod = await loadMarkdownModule();
	return mod.FormMarkdownEditor;
}

/**
 * Matcher for markdown editor fields.
 * Delegates to the real matcher once the module is loaded;
 * returns false if the module hasn't been loaded yet.
 */
export function markdownEditorFieldMatcher(schema: { format?: string }): boolean {
	return _markdownModule?.markdownEditorFieldMatcher(schema) ?? false;
}

/**
 * Register the markdown editor field component (lazy-loads EasyMDE)
 */
export async function registerMarkdownEditorField(priority?: number): Promise<void> {
	const mod = await loadMarkdownModule();
	mod.registerMarkdownEditorField(priority);
}

/**
 * Register markdown editor field using an already-imported component (lazy-loads module)
 */
export async function registerMarkdownEditorFieldWithComponent(component: Component, priority?: number): Promise<void> {
	const mod = await loadMarkdownModule();
	mod.registerMarkdownEditorFieldWithComponent(component, priority);
}

/**
 * Check if markdown editor field is registered.
 * Returns false if the module hasn't been loaded yet.
 */
export function isMarkdownEditorRegistered(): boolean {
	return _markdownModule?.isMarkdownEditorRegistered() ?? false;
}

// ============================================================================
// Form Full Module Exports (all field types initialization) — Lazy-loaded
// ============================================================================

/**
 * Initialize all form field types including heavy editors (lazy-loads CodeMirror + EasyMDE)
 */
export async function initializeAllFieldTypes(): Promise<void> {
	const mod = await import("@d34dman/flowdrop/form/full");
	mod.initializeAllFieldTypes();
}

/**
 * Check if all field types have been initialized.
 * Loads the module to check the actual state.
 */
export async function areAllFieldTypesInitialized(): Promise<boolean> {
	const mod = await import("@d34dman/flowdrop/form/full");
	return mod.areAllFieldTypesInitialized();
}

/**
 * Reset initialization state (useful for testing).
 * Loads the module to reset the actual state.
 */
export async function resetFieldTypeInitialization(): Promise<void> {
	const mod = await import("@d34dman/flowdrop/form/full");
	mod.resetFieldTypeInitialization();
}

// ============================================================================
// Playground Exports — Lazy-loaded
// ============================================================================
// Playground is a separate feature that can be used independently of the
// editor. It's lazy-loaded so pages that only use the editor or schema form
// don't pay the cost of playground code.

/** Cached module reference for @d34dman/flowdrop/playground */
let _playgroundModule: typeof import("@d34dman/flowdrop/playground") | null = null;

/** Load the playground module on demand */
async function loadPlaygroundModule() {
	if (!_playgroundModule) {
		_playgroundModule = await import("@d34dman/flowdrop/playground");
	}
	return _playgroundModule;
}

/**
 * Mount a playground instance (lazy-loads playground chunk)
 */
export async function mountPlayground(
	container: HTMLElement,
	options: PlaygroundMountOptions
): Promise<MountedPlayground> {
	const mod = await loadPlaygroundModule();
	return mod.mountPlayground(container, options);
}

/**
 * Unmount a playground instance (lazy-loads playground chunk if not loaded)
 */
export async function unmountPlayground(app: MountedPlayground): Promise<void> {
	const mod = await loadPlaygroundModule();
	mod.unmountPlayground(app);
}

// ============================================================================
// Custom Mount Functions for Drupal / Vanilla JS Integration
// ============================================================================

import { mount, unmount } from "svelte";
import type { SchemaFormProps } from "@d34dman/flowdrop/form";
import { SchemaForm } from "@d34dman/flowdrop/form";

/**
 * Type alias for the Svelte component instance
 */
type SchemaFormComponent = ReturnType<typeof mount>;

/**
 * Interface for the mounted SchemaForm instance
 */
export interface MountedSchemaForm {
	/** Unmount the SchemaForm component and clean up resources */
	destroy: () => void;
	/** Reference to the underlying Svelte component instance */
	component: SchemaFormComponent;
}

/**
 * Mount options for the SchemaForm component
 */
export interface MountSchemaFormOptions {
	/** JSON Schema defining the form structure */
	schema: SchemaFormProps["schema"];
	/** Current form values as key-value pairs */
	values?: SchemaFormProps["values"];
	/** Callback fired when form values change */
	onChange?: SchemaFormProps["onChange"];
	/** Whether to display Save and Cancel action buttons */
	showActions?: SchemaFormProps["showActions"];
	/** Label text for the save button */
	saveLabel?: SchemaFormProps["saveLabel"];
	/** Label text for the cancel button */
	cancelLabel?: SchemaFormProps["cancelLabel"];
	/** Callback fired when the Save button is clicked */
	onSave?: SchemaFormProps["onSave"];
	/** Callback fired when the Cancel button is clicked */
	onCancel?: SchemaFormProps["onCancel"];
	/** Whether the form is in a loading state */
	loading?: SchemaFormProps["loading"];
	/** Whether the form is disabled */
	disabled?: SchemaFormProps["disabled"];
	/** Custom CSS class to apply to the form container */
	class?: SchemaFormProps["class"];
}

/**
 * Mounts a SchemaForm component into the specified container element
 *
 * @param container - The DOM element or CSS selector to mount the form into
 * @param options - Configuration options for the SchemaForm
 * @returns A MountedSchemaForm object with methods to control the mounted instance
 *
 * @example
 * ```typescript
 * const form = mountSchemaForm("#form-container", {
 *   schema: { type: "object", properties: { name: { type: "string" } } },
 *   values: { name: "John" },
 *   onChange: (values) => console.log("Form changed:", values),
 *   onSave: (values) => console.log("Saving:", values)
 * });
 *
 * // Later, cleanup
 * form.destroy();
 * ```
 */
export function mountSchemaForm(
	container: HTMLElement | string,
	options: MountSchemaFormOptions
): MountedSchemaForm {
	const targetElement =
		typeof container === "string"
			? document.querySelector<HTMLElement>(container)
			: container;

	if (!targetElement) {
		throw new Error(
			`SchemaForm mount error: Container element not found. ` +
			`Provided: ${typeof container === "string" ? container : "HTMLElement"}`
		);
	}

	if (!options.schema) {
		throw new Error("SchemaForm mount error: 'schema' prop is required");
	}

	const props: SchemaFormProps = {
		schema: options.schema
	};

	if (options.values !== undefined) props.values = options.values;
	if (options.onChange !== undefined) props.onChange = options.onChange;
	if (options.showActions !== undefined) props.showActions = options.showActions;
	if (options.saveLabel !== undefined) props.saveLabel = options.saveLabel;
	if (options.cancelLabel !== undefined) props.cancelLabel = options.cancelLabel;
	if (options.onSave !== undefined) props.onSave = options.onSave;
	if (options.onCancel !== undefined) props.onCancel = options.onCancel;
	if (options.loading !== undefined) props.loading = options.loading;
	if (options.disabled !== undefined) props.disabled = options.disabled;
	if (options.class !== undefined) props.class = options.class;

	const mountOptions = {
		target: targetElement,
		props
	};

	const component = mount(
		SchemaForm,
		mountOptions as Parameters<typeof mount>[1]
	);

	const mountedInstance: MountedSchemaForm = {
		destroy: () => {
			unmount(component);
		},
		component
	};

	return mountedInstance;
}
