/**
 * skill-router: pure function to map inbound A2A message to piece/space
 * constrained to delegation's effective skills (fail-closed).
 */

export interface SelectPieceForMessageOpts {
  messageText: string;
  effectiveSkills: string[];
  effectiveSpaceIds: string[];
  requestedSkillId?: string;
}

export interface SelectPieceForMessageResult {
  pieceName: string;
  spaceId: string;
}

/**
 * Maps an inbound A2A message to a piece and space, respecting delegation constraints.
 *
 * Rules (fail-closed):
 * - If `effectiveSkills` is empty OR `effectiveSpaceIds` is empty → return null
 * - If `requestedSkillId` is provided: use it ONLY if in `effectiveSkills`; else return null
 * - If `requestedSkillId` absent: default to `effectiveSkills[0]`
 * - `spaceId` is always `effectiveSpaceIds[0]`
 * - Returned `pieceName` is always a member of `effectiveSkills`
 *
 * @param opts - Options object containing message and authorization constraints
 * @returns Object with { pieceName, spaceId } or null if constraints fail
 */
export function selectPieceForMessage(
  opts: SelectPieceForMessageOpts,
): SelectPieceForMessageResult | null {
  const { messageText, effectiveSkills, effectiveSpaceIds, requestedSkillId } =
    opts;

  // Fail-closed: no skills available
  if (!effectiveSkills || effectiveSkills.length === 0) {
    return null;
  }

  // Fail-closed: no spaces available
  if (!effectiveSpaceIds || effectiveSpaceIds.length === 0) {
    return null;
  }

  // Determine which skill to use
  let selectedSkill: string;

  if (requestedSkillId !== undefined) {
    // Requested skill must be in effectiveSkills; fail-closed if not
    if (!effectiveSkills.includes(requestedSkillId)) {
      return null;
    }
    selectedSkill = requestedSkillId;
  } else {
    // No explicit request: default to first available skill
    selectedSkill = effectiveSkills[0];
  }

  // Always use first available space
  const selectedSpace = effectiveSpaceIds[0];

  return {
    pieceName: selectedSkill,
    spaceId: selectedSpace,
  };
}
