/**
 * Runtime registry singleton that controls live vs static behavior.
 * Consumers can call `registry.setDesigner(designer)` to enable live mode
 * or `registry.setStaticMode(paths)` to point to static asset modules.
 */
export interface PDSRegistry {
  /** Attach a designer instance and switch the registry to live mode. */
  setDesigner(designer: any, meta?: { presetName?: string }): void;
  /** Switch to static mode and override static paths (keys: tokens, primitives, components, utilities, styles) */
  setStaticMode(paths?: Record<string, string>): void;
  /** Return a constructable stylesheet for the requested layer or null on failure. */
  getStylesheet(layer: string): Promise<CSSStyleSheet | null>;
  /** Return a BLOB URL (live mode only) for layer imports used in CSS */
  getBlobURL(layer: string): string | null;
  /** 'live' or 'static' */
  readonly mode: string;
  /** true when a live designer instance is registered */
  readonly isLive: boolean;
  /** true when a designer instance exists */
  readonly hasDesigner: boolean;
}

/** A small shape describing component metadata used by the PDS ontology. */
export interface ComponentDef {
  /** canonical name of the component (e.g., 'Button') */
  name: string;
  /** optional HTML tag name for the component ('pds-button') */
  tag?: string;
  /** documented props and their types/metadata */
  props?: Record<string, any>;
  /** human-friendly description used by the designer */
  description?: string;
}

/** Layer information with CSS content and metadata */
export interface CompiledLayer {
  css: string;
  size: number;
  sizeKB: string;
}

/** Complete compiled state of the design system */
export interface CompiledState {
  /** Core token groups - the source data used to generate CSS */
  tokens: {
    colors: Record<string, any>;
    spacing: Record<string, any>;
    radius: Record<string, any>;
    borderWidths: Record<string, any>;
    typography: Record<string, any>;
    shadows: Record<string, any>;
    layout: Record<string, any>;
    transitions: Record<string, any>;
    zIndex: Record<string, any>;
    icons: Record<string, any>;
  };

  /** Layer information - CSS content and metadata for each layer */
  layers: {
    tokens: CompiledLayer;
    primitives: CompiledLayer;
    components: CompiledLayer;
    utilities: CompiledLayer;
    combined: CompiledLayer;
  };

  /** Configuration snapshot - what was used to generate this state */
  config: {
    design: any;
    preset: string | null;
    debug: boolean;
  };

  /** Runtime capabilities and environment */
  capabilities: {
    constructableStylesheets: boolean;
    blobURLs: boolean;
    shadowDOM: boolean;
  };

  /** References to design system metadata */
  references: {
    ontology: any;
    enums: any;
  };

  /** Computed metadata about the generated design system */
  meta: {
    generatedAt: string;
    totalSize: number;
    totalSizeKB: string;
    layerCount: number;
    tokenGroups: number;
  };

  /** Introspection helpers - methods to query the compiled state */
  helpers: {
    getColorScales(): Array<{ name: string; scale: any }>;
    getColorScale(name: string): any;
    getSpacingValues(): Array<{ key: string; value: any }>;
    getTypography(): any;
    getLayerCSS(layer: 'tokens' | 'primitives' | 'components' | 'utilities'): string;
    usesEnumValue(enumGroup: string, value: any): boolean;
  };
}

/** Public config types for editor IntelliSense */
export type PDSInitConfig = import("./pds-core/pds-config.js").PDSInitConfig;

/**
 * Generator - programmatic API to produce tokens, layered CSS and helper modules from a config.
 * Typical usage:
 * const g = new Generator({ example: true });
 * // tokens may be returned synchronously or via a Promise
 * const tokens = await g.generateTokens?.();
 * const css = await g.generateCSS?.();
 */
export class Generator {
  constructor(options?: any);
  /** runtime options / config passed to the generator */
  options: any;
  /** generated token object */
  tokens: Record<string, any>;
  /** concatenated CSS (layered) */
  css: string;
  /** Complete compiled representation of the design system state */
  readonly compiled: CompiledState;
  /** Generate the token map (may be async in some implementations) */
  generateTokens?(): Record<string, any> | Promise<Record<string, any>>;
  /** Generate the CSS string (may be async) */
  generateCSS?(): string | Promise<string>;
}

export interface GeneratorRuntimeExports {
  Generator: typeof Generator;
  applyStyles: (generator?: Generator) => void;
  adoptLayers: (
    shadowRoot: ShadowRoot,
    layers?: string[],
    additionalSheets?: CSSStyleSheet[]
  ) => Promise<void>;
  adoptPrimitives: (
    shadowRoot: ShadowRoot,
    additionalSheets?: CSSStyleSheet[]
  ) => Promise<void>;
  createStylesheet: (css: string) => CSSStyleSheet;
  [key: string]: any;
}

/** Public runtime surface exported as `PDS` */
export interface PDSEventMap {
  'pds:ready': CustomEvent<{ mode: 'live' | 'static'; generator?: Generator; config: any; theme: string; autoDefiner?: any }>;
  'pds:error': CustomEvent<{ error: any }>;
  'pds:theme:changed': CustomEvent<{ theme: string; requested?: string; source: 'system' | 'programmatic' }>;
  'pds:config-changed': CustomEvent<{ at: number; mode?: 'live' | 'static'; source?: string; preset?: string }>;
  'pds:design:updated': CustomEvent<{ config: any; designer?: any }>;
  'pds:design:field:changed': CustomEvent<{ field: string; config: any }>;
  'pds:inspector:mode:changed': CustomEvent<{ active: boolean }>;
  'pds:inspector:deactivate': CustomEvent<{}>;
  'pds:docs:view': CustomEvent<{ file: string }>;
}

export class PDS extends EventTarget {
  // Static surface
  static registry: PDSRegistry;
  static initializing?: boolean;
  static currentPreset?: string | null;
  static debug?: boolean;
  static applyStyles?: (generator?: Generator) => void;
  static adoptLayers: (shadowRoot: ShadowRoot, layers?: string[], additionalSheets?: CSSStyleSheet[]) => Promise<void>;
  static adoptPrimitives: (shadowRoot: ShadowRoot, additionalSheets?: CSSStyleSheet[]) => Promise<void>;
  static createStylesheet: (css: string) => CSSStyleSheet;
  static ensureGenerator(): Promise<GeneratorRuntimeExports>;
  static getGenerator?: () => Promise<typeof Generator>;
  static isLiveMode: () => boolean;
  static findComponentForElement?: (el: Element) => ComponentDef | null;
  static presets?: Record<string, any>;
  static configRelations?: Record<string, any>;
  static configSpec?: Record<string, any> | null;
  static configEditorMetadata?: Record<string, any>;
  static configFormSchema?: {
    schema: Record<string, any>;
    uiSchema: Record<string, any>;
    values: Record<string, any>;
    metadata: Record<string, any>;
  } | null;
  static buildConfigFormSchema?: (designConfig?: Record<string, any>) => {
    schema: Record<string, any>;
    uiSchema: Record<string, any>;
    values: Record<string, any>;
    metadata: Record<string, any>;
  };
  static buildPresetOmniboxSettings?: (options?: {
    hideCategory?: boolean;
    includeIncompatible?: boolean;
    disableIncompatible?: boolean;
    categoryName?: string;
    theme?: string | null;
    onSelect?: (context: {
      preset: Record<string, any>;
      selection: Record<string, any>;
      resolvedTheme: string;
    }) => Promise<any> | any;
    iconHandler?: (item: Record<string, any>) => string;
  }) => Record<string, any>;
  static getConfigEditorMetadata?: (designConfig?: Record<string, any>) => Record<string, any>;
  static enhancerMetadata?: Array<{ selector: string; description?: string; demoHtml?: string }>;
  static defaultEnhancers?: Array<any>;
  static ontology?: any;
  static enums?: Record<string, any>;
  static common?: Record<string, any>;
  static parse?: (html: string) => Element[];
  static query?: (question: string) => Promise<any[]>;
  static AutoComplete?: any;
  static loadAutoComplete?: () => Promise<any>;
  
  /**
   * Display a toast notification.
   * 
   * Automatically ensures the pds-toaster component exists and is loaded before displaying.
   * 
   * @param message - The message to display
   * @param options - Toast configuration
   * @param options.type - Toast type/severity ("information" | "success" | "warning" | "error")
   * @param options.duration - Duration in milliseconds (auto-calculated if not provided)
   * @param options.closable - Whether toast can be manually closed (default: true)
   * @param options.persistent - If true, toast won't auto-dismiss (default: false)
   * @returns Toast ID (can be used to dismiss programmatically)
   * 
   * @example
   * await PDS.toast('Changes saved!', { type: 'success' });
   * 
   * @example
   * await PDS.toast('Error occurred', { type: 'error', persistent: true });
   */
  static toast(
    message: string,
    options?: {
      type?: 'information' | 'success' | 'warning' | 'error';
      duration?: number;
      closable?: boolean;
      persistent?: boolean;
    }
  ): Promise<string>;
  
  /**
   * Display a success toast (convenience method).
   * 
   * @param message - The success message
   * @param options - Additional toast options (type is preset to 'success')
   * @returns Toast ID
   * 
   * @example
   * await PDS.toast.success('Profile updated!');
   */
  static toast: {
    (message: string, options?: { type?: 'information' | 'success' | 'warning' | 'error'; duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
    success(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
    error(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
    warning(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
    info(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
  };
  
  /**
   * Display a modal dialog for user input or confirmation.
   * 
   * @param message - The message or prompt to display
   * @param options - Dialog configuration
   * @returns User's response (string for prompt, boolean for confirm, true for alert)
   * 
   * @example
   * const confirmed = await PDS.ask('Delete this item?', { type: 'confirm' });
   * 
   * @example
   * const name = await PDS.ask('Enter your name:', { type: 'prompt' });
   */
  static ask(message: string, options?: any): Promise<any>;
  
  /** 
   * Current configuration after PDS.start() completes - read-only, frozen after initialization.
   * Contains the complete configuration used to initialize PDS, including mode, design, preset, and theme.
   */
  static readonly currentConfig: any;
  
  /**
   * Compiled design system state - provides structured access to all generated tokens,
   * layers, and metadata. Available in live mode when a generator is active.
   * Returns null if not in live mode or if no generator is present.
   */
  static readonly compiled?: CompiledState | null;

  // Static EventTarget-like facade for default instance
  static addEventListener<K extends keyof PDSEventMap>(type: K, listener: (ev: PDSEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
  static removeEventListener<K extends keyof PDSEventMap>(type: K, listener: (ev: PDSEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
  static dispatchEvent(event: PDSEventMap[keyof PDSEventMap] | Event): boolean;

  // Static entry point
  static start(config?: {
    mode?: 'live' | 'static';
    preset?: string;
    design?: any;
    autoDefine?: {
      baseURL?: string;
      predefine?: string[];
      mapper?: (tag: string) => string | undefined | null | false;
      scanExisting?: boolean;
      observeShadows?: boolean;
      patchAttachShadow?: boolean;
      debounceMs?: number;
      onError?: (tag: string, err: any) => void;
    };
    applyGlobalStyles?: boolean;
    manageTheme?: boolean;
    themeStorageKey?: string;
    public?: {
      root?: string;
      managerURL?: string;
    };
    // live-only
    preloadStyles?: boolean;
    criticalLayers?: string[];
    managerURL?: string;
    // static-only
    staticPaths?: Record<string, string>;
    enhancers?: Array<any>;
  }): Promise<PDS>;

  static preloadCritical?: (config: any, options?: { theme?: string; layers?: string[] }) => void;

  constructor();

  // Instance state
  readonly mode: 'live' | 'static';
  readonly generator?: Generator;
  readonly config: any;
  readonly theme: string;
  readonly autoDefiner?: any;

  // Instance helpers
  preloadCritical?(config: any, options?: { theme?: string; layers?: string[] }): void;
}

export { PDS as default };

// ===== pds-form Types =====

export interface JsonFormOptions {
  widgets?: {
    booleans?: 'toggle' | 'checkbox';
    numbers?: 'input' | 'range';
    selects?: 'standard' | 'dropdown';
  };
  layouts?: {
    fieldsets?: 'default' | 'flex' | 'grid' | 'accordion' | 'tabs' | 'card';
    arrays?: 'default' | 'compact';
  };
  enhancements?: {
    icons?: boolean;
    datalists?: boolean;
    rangeOutput?: boolean;
    colorInput?: boolean;
  };
  validation?: {
    showErrors?: boolean;
    validateOnChange?: boolean;
  };
  // Path-specific options (JSON Pointer paths)
  [path: string]: any;
}

export interface UISchema {
  // Field-level UI customization (JSON Pointer paths as keys)
  [path: string]: {
    'ui:widget'?: string;
    'ui:layout'?: 'default' | 'flex' | 'grid' | 'accordion' | 'tabs';
    'ui:columns'?: number | 'auto';
    'ui:autoSize'?: 'sm' | 'md' | 'lg' | 'xl';
    'ui:gap'?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
    'ui:wrap'?: boolean;
    'ui:direction'?: 'row' | 'column';
    'ui:surface'?: 'card' | 'elevated' | 'dialog';
    'ui:accordion'?: boolean;
    'ui:tabs'?: boolean;
    'ui:defaultOpen'?: number[];
    'ui:dialog'?: boolean;
    'ui:dialogButton'?: string;
    'ui:dialogSize'?: 'sm' | 'lg' | 'xl' | 'full';
    'ui:submitLabel'?: string;
    'ui:cancelLabel'?: string;
    'ui:help'?: string;
    'ui:placeholder'?: string;
    'ui:icon'?: string;
    'ui:iconPosition'?: 'start' | 'end';
    'ui:datalist'?: string[];
    'ui:rows'?: number;
    'ui:min'?: number;
    'ui:max'?: number;
    'ui:dropdown'?: boolean;
    'ui:autocomplete'?: string;
    'ui:accept'?: string;
    'ui:multiple'?: boolean;
    'ui:maxFiles'?: number;
    'ui:maxSize'?: number;
    'ui:submitOnEnter'?: boolean;
    'ui:spellcheck'?: boolean;
    'ui:order'?: string[];
  };
}

export interface JsonFormEvent<T = any> extends CustomEvent {
  detail: T;
}

export interface JsonFormSubmitDetail {
  json: any;
  formData: FormData;
  valid: boolean;
  issues: Array<{ path?: string; message: string }>;
}

export interface JsonFormValueChangeDetail {
  name: string;
  value: any;
  validity: { valid: boolean };
}

export interface JsonFormArrayEventDetail {
  path: string;
  index?: number;
  from?: number;
  to?: number;
}

export interface JsonFormDialogEventDetail {
  path: string;
  schema?: any;
  value?: any;
}

export interface JsonFormRendererContext {
  id: string;
  path: string;
  label: string;
  value: any;
  required: boolean;
  ui: any;
  schema: any;
  get: (path?: string) => any;
  set: (value: any, path?: string) => void;
  attrs: {
    placeholder?: string;
    minLength?: number;
    maxLength?: number;
    min?: number;
    max?: number;
    step?: number;
    pattern?: string;
    readOnly?: boolean;
    required?: boolean;
    autocomplete?: string;
    list?: string;
  };
  host: any;
}

export type JsonFormRenderer = (context: JsonFormRendererContext) => any;

export interface JsonFormEventMap {
  'pw:schema-resolve': JsonFormEvent<{ schema: any }>;
  'pw:compile-node': JsonFormEvent<{ path: string; schema: any; ui: any; node?: any }>;
  'pw:choose-widget': JsonFormEvent<{ path: string; schema: any; ui: any; widget: string | null }>;
  'pw:before-render-field': JsonFormEvent<{ path: string; schema: any; ui: any; mount?: any; render?: () => any }>;
  'pw:render-field': JsonFormEvent<{ path: string; schema: any; node: any }>;
  'pw:after-render-field': JsonFormEvent<{ path: string; schema: any }>;
  'pw:value-change': JsonFormEvent<JsonFormValueChangeDetail>;
  'pw:array-add': JsonFormEvent<JsonFormArrayEventDetail>;
  'pw:array-remove': JsonFormEvent<JsonFormArrayEventDetail>;
  'pw:array-reorder': JsonFormEvent<JsonFormArrayEventDetail>;
  'pw:serialize': JsonFormEvent<JsonFormSubmitDetail>;
  'pw:submit': JsonFormEvent<JsonFormSubmitDetail>;
  'pw:dialog-open': JsonFormEvent<JsonFormDialogEventDetail>;
  'pw:dialog-submit': JsonFormEvent<JsonFormDialogEventDetail>;
}

declare global {
  interface HTMLElementTagNameMap {
    'pds-form': SchemaForm;
  }
}

export class SchemaForm extends HTMLElement {
  // Properties
  jsonSchema: any;
  uiSchema: UISchema;
  options: JsonFormOptions;
  values: any;
  action?: string;
  method: 'get' | 'post' | 'dialog';
  disabled: boolean;
  hideActions: boolean;
  submitLabel: string;
  resetLabel: string;
  hideReset: boolean;
  hideSubmit: boolean;

  // Methods
  defineRenderer(widgetKey: string, renderer: JsonFormRenderer): void;
  useValidator(validator: (data: any, schema: any) => Promise<{ valid: boolean; errors?: Array<{ path?: string; message: string }> }>): void;
  getValuesFlat(): Record<string, any>;
  serialize(): { json: any; formData: FormData };
  submit(): Promise<JsonFormSubmitDetail>;

  // Event listeners
  addEventListener<K extends keyof JsonFormEventMap>(
    type: K,
    listener: (ev: JsonFormEventMap[K]) => any,
    options?: boolean | AddEventListenerOptions
  ): void;
  addEventListener(
    type: string,
    listener: EventListenerOrEventListenerObject,
    options?: boolean | AddEventListenerOptions
  ): void;
  removeEventListener<K extends keyof JsonFormEventMap>(
    type: K,
    listener: (ev: JsonFormEventMap[K]) => any,
    options?: boolean | EventListenerOptions
  ): void;
  removeEventListener(
    type: string,
    listener: EventListenerOrEventListenerObject,
    options?: boolean | EventListenerOptions
  ): void;
}
