/**
 * Skill preferences — declarative per-skill settings.
 *
 * When a skill declares preferences, dddk:
 *   1. Refuses to run the skill until all `required: true` prefs are filled.
 *   2. Auto-renders a setup form (as a Surface) the first time.
 *   3. Stores values keyed by skill id via the dddk StorageAdapter.
 *   4. Provides `ctx.getPreferences<T>()` inside the skill handler.
 */

type PreferenceKind = 'text' | 'password' | 'number' | 'checkbox' | 'select';
interface PreferenceField {
    name: string;
    title: string;
    kind: PreferenceKind;
    description?: string;
    required?: boolean;
    default?: unknown;
    placeholder?: string;
    /** For 'select' kind. */
    options?: Array<{
        value: string;
        label: string;
    }>;
}

/**
 * Skill type definitions — 4 kinds: Script / Prompt / Action / Surface
 * See ../../docs/05-skills-sdk.md for the full design.
 */
interface ScriptStep {
    page?: string;
    subtitle?: string;
    action?: (tools: SkillTools) => void | Promise<void>;
    waitForUser?: boolean;
}
interface SkillTools {
    navigate(path: string): void;
    highlight(selector: string, color?: string, label?: string): string;
    border(selector: string, color?: string, label?: string): string;
    spotlight(selector: string): string;
    inject(selector: string, text: string, position?: 'before' | 'after'): string;
    subtitle(text: string): void;
    clearOverlays(): void;
    ask(question: string): Promise<string>;
    wait(ms: number): Promise<void>;
    llm?(prompt: string): Promise<string>;
    runSkill?(id: string, vars?: Record<string, string>): Promise<void>;
    /**
     * Show an ad-hoc Surface (form / dialog / picker) mid-script and await the
     * user's submission. Resolves with the form data when the host calls
     * `dddk.submitSurface(data)`, or `null` if the user cancels via
     * `dddk.cancelSurface()` / Esc.
     *
     * The surface argument is a `PieceSurface` (root PieceNode + optional data).
     * `placement` defaults to `'modal'` (full-screen popup); use `'subtitle'`
     * for the subtitle bar, `'dock'` for a persistent side panel.
     */
    surface(surface: unknown, opts?: {
        placement?: SurfacePlacement;
    }): Promise<Record<string, unknown> | null>;
}
/**
 * Surface placement (revised 2026-05-22).
 *
 * - `palette`  — render inside an active PanelSkill's content area
 * - `subtitle` — render in the existing subtitle bar (lightest, ignorable)
 * - `dock`     — persistent side panel, user can minimize/close
 * - `modal`    — full-screen popup with backdrop (canonical "popup", supports forms)
 */
type SurfacePlacement = 'palette' | 'subtitle' | 'dock' | 'modal';
interface BaseSkill {
    id: string;
    name: string;
    description?: string;
    icon?: string;
    /** Hide from palette listing (still callable). */
    hidden?: boolean;
    /** Function returning whether this skill is currently visible to the user. */
    visible?: (ctx: {
        user?: unknown;
    }) => boolean;
    /**
     * Declarative preferences. If any `required: true` field is unfilled,
     * dddk auto-renders a setup Surface form before dispatching the skill.
     * See ./preferences.ts
     */
    preferences?: Array<PreferenceField>;
}
interface ScriptSkill extends BaseSkill {
    type: 'script';
    steps: ScriptStep[];
}
interface PromptSkill extends BaseSkill {
    type: 'prompt';
    /** System prompt or prompt template. Use `{{var}}` placeholders. */
    prompt: string;
    variables?: Record<string, string>;
}
interface ActionSkillContext {
    palette: {
        close(): void;
        replace(items: Array<{
            id: string;
            name: string;
            handler: () => void;
        }>): void;
    };
    subtitle: {
        show(opts: {
            text: string;
            type?: string;
            autoHide?: number;
        }): void;
        hide(): void;
    };
    storage: {
        get<T = string>(key: string): T | null;
        set(key: string, value: unknown): void;
    };
    /** Read this skill's declared preferences (empty object if no schema). */
    getPreferences<T = Record<string, unknown>>(): T;
    llm?(prompt: string): Promise<string>;
    agent?(task: string): void;
    navigate(path: string): void;
}
interface ActionSkill extends BaseSkill {
    type: 'action';
    handler: (ctx: ActionSkillContext) => void | Promise<void>;
}
interface SurfaceSkillContext extends ActionSkillContext {
}
interface SurfaceSkill extends BaseSkill {
    type: 'surface';
    build: (ctx: SurfaceSkillContext) => Promise<unknown>;
    onSubmit?: (data: Record<string, unknown>, ctx: SurfaceSkillContext) => Promise<unknown> | unknown;
}
interface PanelSkillContext extends ActionSkillContext {
    /** Render a new PieceSurface into the panel area. */
    render(surface: unknown): void;
    /** Pop this panel skill off the navigation stack. */
    back(): void;
    /** Update the input box's placeholder. */
    setPlaceholder(text: string): void;
}
interface PanelSkill extends BaseSkill {
    type: 'panel';
    /**
     * `palette`  — keep slash-command routing + ask-AI fallback; free-text goes
     *              to onInput. Best for search / recommend / qa / classify.
     * `takeover` — input is purely passed to onInput. No command parsing.
     *              Best for chat / continuous webagent.
     */
    inputMode: 'palette' | 'takeover';
    /** Custom placeholder for the input box while in this skill. */
    inputPlaceholder?: string;
    /** Called once when the skill is entered (empty input). */
    onEnter?: (ctx: PanelSkillContext) => Promise<unknown> | unknown;
    /** Called on every input change (debounced by the palette renderer). */
    onInput: (text: string, ctx: PanelSkillContext) => Promise<unknown> | unknown;
    /** Called when the user submits (Enter). Optional; many panels use onInput live. */
    onSubmit?: (text: string, ctx: PanelSkillContext) => Promise<unknown> | unknown;
    /** Called when the user activates a piece action inside the panel. */
    onAction?: (action: string, data: unknown, ctx: PanelSkillContext) => Promise<unknown> | unknown;
    /** Called when the skill is popped from the stack. */
    onLeave?: () => Promise<void> | void;
}
type Skill = ScriptSkill | PromptSkill | ActionSkill | SurfaceSkill | PanelSkill;

/**
 * SkillRegistry — register / lookup / match skills by id or `/command`.
 */

declare class SkillRegistry {
    private skills;
    constructor(initial?: Skill[]);
    register(skill: Skill): void;
    unregister(id: string): void;
    get(id: string): Skill | undefined;
    list(): Skill[];
    listAll(): Skill[];
    /** Match palette input like `/introduce` or `/translate en` to a skill id. */
    match(input: string): Skill | undefined;
    /** Extract args after the skill name. e.g. `/translate en` → 'en' */
    parseArgs(input: string): string;
    /** Resolve `{{var}}` placeholders in a PromptSkill template. */
    resolvePrompt(skill: PromptSkill, vars?: Record<string, string>): string;
}

export { type ActionSkill, type ActionSkillContext, type BaseSkill, type PanelSkill, type PanelSkillContext, type PromptSkill, type ScriptSkill, type ScriptStep, type Skill, SkillRegistry, type SkillTools, type SurfacePlacement, type SurfaceSkill, type SurfaceSkillContext };
