/**
 * Nest dependency-injection tokens for the harness-neutral registry and service.
 *
 * String tokens follow the existing Gateway convention (see `memory/memory.tokens.ts`)
 * and remain valid Nest `InjectionToken`s for `@Inject(...)`.
 */
import type { HarnessConversationService } from '@mosaicstack/types';

export const HARNESS_REGISTRY = 'HARNESS_REGISTRY' as const;
export const HARNESS_SERVICE = 'HARNESS_SERVICE' as const;

export type HarnessRegistryToken = typeof HARNESS_REGISTRY;
export type HarnessServiceToken = typeof HARNESS_SERVICE;

/**
 * Token for the {@link HarnessConversationService} that {@link HarnessChatRuntime}
 * depends on. Until Task 14 provides a real implementation, `HarnessModule` binds
 * the {@link HARNESS_CONVERSATION_SERVICE_UNAVAILABLE} sentinel here, and the
 * `pi-rpc` router treats that sentinel as a hard, typed startup failure.
 */
export const HARNESS_CONVERSATION_SERVICE = 'HARNESS_CONVERSATION_SERVICE' as const;

export type HarnessConversationServiceToken = typeof HARNESS_CONVERSATION_SERVICE;

/**
 * Explicit "not yet bound" value for {@link HARNESS_CONVERSATION_SERVICE}. It is a
 * distinct sentinel — never `null`/`undefined` — so an unbound service is an
 * intentional, checkable state rather than an accidental nil that could read as
 * "present". Replaced by a real service in Task 14.
 */
export const HARNESS_CONVERSATION_SERVICE_UNAVAILABLE: unique symbol = Symbol(
  'HARNESS_CONVERSATION_SERVICE_UNAVAILABLE',
);

/** A binding for {@link HARNESS_CONVERSATION_SERVICE}: a real service or the sentinel. */
export type HarnessConversationServiceBinding =
  | HarnessConversationService
  | typeof HARNESS_CONVERSATION_SERVICE_UNAVAILABLE;

/** Narrows a binding to a usable service, excluding the unavailable sentinel. */
export function isHarnessConversationServiceAvailable(
  binding: HarnessConversationServiceBinding,
): binding is HarnessConversationService {
  return binding !== HARNESS_CONVERSATION_SERVICE_UNAVAILABLE;
}
