/**
 * State of the AI assistant component.
 *
 * `cancelling` is a refinement of `loading`: a stop was requested but the turn
 * is still winding down (e.g. a tool mid-execution finishing). It is "busy"
 * like `loading` — use the host's `busy` getter for "is a turn active" gates.
 *
 * @beta
 */
export type AiAssistantState = 'idle' | 'loading' | 'cancelling' | 'error';

/**
 * Controls the pop-out button shown in the assistant header.
 * - `"expand"` — assistant is embedded in the bubble dialog; button expands it to a layout panel.
 * - `"collapse"` — assistant is in a layout panel; button collapses it back to the bubble.
 *
 * @beta
 */
export type PopoutMode = 'expand' | 'collapse';

export type { AgentPickerMode } from '@genesislcap/foundation-ai';

/**
 * Result returned by {@link FoundationAiAssistant.submitMessage}.
 *
 * `ok` is `false` when the assistant is busy, the message is empty, or any
 * supplied file failed validation — in which case no send was dispatched and
 * `errors` lists the reasons.
 *
 * @beta
 */
export interface SubmitMessageResult {
  ok: boolean;
  errors: string[];
}

/**
 * `detail` of the `AiAssistantEvent.SessionCleared` event. Captured *before*
 * teardown so a host can tidy up whatever the active agent was working on
 * (generated files, server-side scratch, …). `agentSnapshot` is the agent's
 * `serialize()` output (a state-machine image for machine-backed agents).
 *
 * @beta
 */
export interface SessionClearedDetail {
  sessionKey: string | undefined;
  agentName: string | undefined;
  agentSnapshot: unknown;
}

/**
 * `detail` of the `AiAssistantEvent.ChatHeaderMouseDown` event.
 *
 * @beta
 */
export interface ChatHeaderMouseDownDetail {
  clientX: number;
  clientY: number;
}

/**
 * DOM events the `<foundation-ai-assistant>` element dispatches to its host.
 * All bubble and are `composed` (they cross the shadow boundary), so a host can
 * listen on the element — or any ancestor — to react. Use these constants to
 * wire listeners instead of hand-typing event-name strings.
 *
 * An `as const` map (not a TS `enum` — this package ships none), so it serves as
 * both the listener-name value and, via the same-named type below, a union.
 *
 * @example
 * ```ts
 * import { AiAssistantEvent, type SessionClearedDetail } from '@genesislcap/ai-assistant';
 *
 * el.addEventListener(AiAssistantEvent.SessionCleared, (e) => {
 *   const { agentName, agentSnapshot } = (e as CustomEvent<SessionClearedDetail>).detail;
 *   // …clean up external state the agent was working on…
 * });
 * ```
 *
 * @beta
 */
export const AiAssistantEvent = {
  /** Session wiped via the lifecycle menu's Clear. `detail`: `SessionClearedDetail`. */
  SessionCleared: 'session-cleared',
  /** Header pressed in `popout-mode="expand"` (drag-to-popout hosts). `detail`: `ChatHeaderMouseDownDetail`. */
  ChatHeaderMouseDown: 'chat-header-mousedown',
} as const;

/**
 * One of the `AiAssistantEvent` event-name values.
 *
 * @beta
 */
export type AiAssistantEvent = (typeof AiAssistantEvent)[keyof typeof AiAssistantEvent];

/**
 * State of the chat suggestions feature.
 *
 * @beta
 */
export type SuggestionsState =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'loaded'; suggestions: string[] }
  | { status: 'error'; message: string };

/**
 * Metadata describing a UI animation in the assistant.
 *
 * @beta
 */
export interface AiAssistantAnimationDef {
  /** Display label shown in the settings multiselect. */
  label: string;
  /** Short description shown beneath the label in the categorized multiselect. */
  description: string;
  /** Group heading the option is listed under in the settings multiselect. */
  category: string;
}

/**
 * Registry of all available animations with their display metadata.
 * Adding an entry here automatically extends the {@link AiAssistantAnimation} type.
 *
 * @remarks
 * `loading` (dots), `waves`, `flowingWaves` and `plasma` are interchangeable
 * styles of the same "is the assistant working" indicator and are therefore
 * grouped under the same {@link AiAssistantAnimationDef.category}. They are
 * mutually exclusive — see `LOADING_STYLE_ANIMATIONS`.
 *
 * @beta
 */
export const ANIMATION_DEFS = {
  loading: {
    label: 'Dots',
    description: 'Shows pulsing dots while the assistant is generating a response.',
    category: 'Loading style',
  },
  waves: {
    label: 'Waves',
    description:
      'Shows glowing sine waves inside a circle while the assistant is generating a response.',
    category: 'Loading style',
  },
  flowingWaves: {
    label: 'Flowing waves',
    description:
      'Shows coloured waves rising and settling from a line while the assistant is generating a response.',
    category: 'Loading style',
  },
  plasma: {
    label: 'Plasma orb',
    description:
      'Shows a glowing plasma sphere with drifting energy while the assistant is generating a response.',
    category: 'Loading style',
  },
  halo: {
    label: 'Halo',
    description:
      'Displays a glowing halo around the assistant avatar while a response is streaming.',
    category: 'Effects',
  },
} satisfies Record<string, AiAssistantAnimationDef>;

/**
 * Union of all available animation names, derived from {@link ANIMATION_DEFS}.
 *
 * @beta
 */
export type AiAssistantAnimation = keyof typeof ANIMATION_DEFS;

/**
 * All available animation names, derived from the registry.
 *
 * @internal
 */
export const ALL_ANIMATIONS = Object.keys(ANIMATION_DEFS) as AiAssistantAnimation[];

/**
 * The interchangeable "assistant is working" loading-indicator styles. At most
 * one of these may be enabled at a time — enabling one disables the other.
 *
 * @internal
 */
export const LOADING_STYLE_ANIMATIONS = [
  'loading',
  'waves',
  'flowingWaves',
  'plasma',
] as const satisfies readonly AiAssistantAnimation[];

/**
 * Animations enabled by default when a consumer opts into the animations
 * feature without specifying an explicit `enabled` list. Keeps the dots loading
 * style (the long-standing default); the waves style is opt-in.
 *
 * @internal
 */
export const DEFAULT_ANIMATIONS: AiAssistantAnimation[] = ['loading', 'halo'];
