import { isLeadMember } from '@shared/utils/leadDetection';
import {
  hasUnsafeProvisionedButNotAliveRuntimeEvidenceWithSpawnContext,
  isBootstrapConfirmedProvisionedButNotAliveFailure,
} from '@shared/utils/teamLaunchFailureReason';
import { buildTeamMemberColorMap } from '@shared/utils/teamMemberColors';

import {
  getParticipantAvatarUrlByIndex,
  LEAD_PARTICIPANT_AVATAR_URL,
  PARTICIPANT_AVATAR_URLS,
} from './memberAvatarCatalog';
import { isHealthyOpenCodeAppMcpConnectivityAdvisory } from './openCodeAdvisoryHealth';

import type {
  LeadActivityState,
  MemberLaunchState,
  MemberRuntimeAdvisory,
  MemberSpawnLivenessSource,
  MemberSpawnStatus,
  MemberSpawnStatusEntry,
  MemberStatus,
  ResolvedTeamMember,
  TeamAgentRuntimeDiagnosticSeverity,
  TeamAgentRuntimeEntry,
  TeamProviderId,
  TeamReviewState,
  TeamTaskStatus,
} from '@shared/types';

/**
 * UI display name for a team member.
 * "team-lead" → "lead"; everything else passes through unchanged.
 * Data layer (store, IPC, backend) must keep the original name untouched.
 */
export function displayMemberName(name: string): string {
  return name === 'team-lead' ? 'lead' : name;
}

function hashStringToIndex(str: string): number {
  let hash = 5381;
  for (let i = 0; i < str.length; i++) {
    hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;
  }
  return Math.abs(hash);
}

export function agentAvatarUrl(name: string, size = 64): string {
  void size;
  const normalized = name.trim().toLowerCase();
  if (normalized === 'team-lead' || normalized === 'lead') {
    return LEAD_PARTICIPANT_AVATAR_URL;
  }

  // Temporarily disabled external avatar API.
  // return `https://robohash.org/${encodeURIComponent(name)}?size=${size}x${size}`;
  return getParticipantAvatarUrlByIndex(
    hashStringToIndex(normalized) % PARTICIPANT_AVATAR_URLS.length
  );
}

export const STATUS_DOT_COLORS: Record<MemberStatus, string> = {
  active: 'bg-emerald-400',
  idle: 'bg-zinc-400',
  terminated: 'bg-red-400',
  unknown: 'bg-zinc-600',
};

export function getMemberDotClass(
  member: ResolvedTeamMember,
  isTeamAlive?: boolean,
  isTeamProvisioning?: boolean,
  leadActivity?: LeadActivityState
): string {
  if (member.status === 'terminated') return STATUS_DOT_COLORS.terminated;
  if (member.removedAt) return STATUS_DOT_COLORS.terminated;
  // Lead activity check BEFORE provisioning fallback — when the lead process
  // is running (CLI logs present), show green even during provisioning.
  if (leadActivity && isLeadMember(member)) {
    return leadActivity === 'active'
      ? `${STATUS_DOT_COLORS.active} animate-pulse`
      : STATUS_DOT_COLORS.active;
  }
  if (isTeamProvisioning) return STATUS_DOT_COLORS.unknown;
  if (isTeamAlive === false) return STATUS_DOT_COLORS.terminated;
  // When team is alive, all non-terminated members are online
  if (isTeamAlive) {
    if (member.currentTaskId) return `${STATUS_DOT_COLORS.active} animate-pulse`;
    return STATUS_DOT_COLORS.active;
  }
  if (member.status === 'unknown') return STATUS_DOT_COLORS.unknown;
  if (member.currentTaskId) return STATUS_DOT_COLORS.active;
  return member.status === 'active' ? STATUS_DOT_COLORS.active : STATUS_DOT_COLORS.idle;
}

export function getPresenceLabel(
  member: ResolvedTeamMember,
  isTeamAlive?: boolean,
  isTeamProvisioning?: boolean,
  leadActivity?: LeadActivityState,
  leadContextPercent?: number
): string {
  if (member.status === 'terminated') return 'terminated';
  // Lead activity check before provisioning fallback (mirrors getMemberDotClass order).
  if (leadActivity && isLeadMember(member)) {
    if (leadActivity === 'active') {
      return leadContextPercent != null && leadContextPercent > 0
        ? `processing (${Math.round(leadContextPercent)}%)`
        : 'processing';
    }
    return 'ready';
  }
  if (isTeamProvisioning) return 'connecting';
  if (isTeamAlive === false) return 'offline';
  if (member.status === 'unknown') return 'idle';
  return member.currentTaskId ? 'working' : 'idle';
}

/* ------------------------------------------------------------------ */
/*  Spawn-status-aware helpers for progressive member card appearance  */
/* ------------------------------------------------------------------ */

export const SPAWN_DOT_COLORS: Record<MemberSpawnStatus, string> = {
  offline: 'bg-zinc-600',
  waiting: 'bg-zinc-400 animate-pulse',
  spawning: 'bg-amber-400',
  online: 'bg-emerald-400 animate-pulse',
  error: 'bg-red-400',
  skipped: 'bg-zinc-500',
};

export const SPAWN_PRESENCE_LABELS: Record<MemberSpawnStatus, string> = {
  offline: 'offline',
  waiting: 'starting',
  spawning: 'starting',
  online: 'ready',
  error: 'spawn failed',
  skipped: 'skipped',
};

const OPENCODE_RUNTIME_CANDIDATE_RELAUNCH_GRACE_MS = 5 * 60 * 1000;
export const MEMBER_STARTING_STALE_AFTER_MS = 2 * 60 * 1000;
const OPENCODE_BRIDGE_OUTCOME_UNKNOWN_AFTER_TIMEOUT_MESSAGE =
  'OpenCode bridge outcome unknown after timeout, retrying/observing.';

function isLaunchStillStarting(
  spawnStatus: MemberSpawnStatus | undefined,
  spawnLaunchState: MemberLaunchState | undefined,
  runtimeAlive: boolean | undefined,
  keepRuntimePendingInStarting = false
): boolean {
  if (spawnLaunchState === 'failed_to_start') {
    return false;
  }
  if (spawnLaunchState === 'skipped_for_launch') {
    return false;
  }
  if (spawnLaunchState === 'runtime_pending_permission') {
    return false;
  }
  if (spawnLaunchState === 'runtime_pending_bootstrap') {
    if (runtimeAlive !== true) {
      return true;
    }
    return keepRuntimePendingInStarting;
  }
  return spawnLaunchState === 'starting' || spawnStatus === 'waiting' || spawnStatus === 'spawning';
}

/**
 * Returns dot class for a member during provisioning, respecting spawn status.
 * Falls back to the existing `getMemberDotClass` when no spawn status is available.
 */
export function getSpawnAwareDotClass(
  member: ResolvedTeamMember,
  spawnStatus: MemberSpawnStatus | undefined,
  spawnLaunchState: MemberLaunchState | undefined,
  runtimeAlive: boolean | undefined,
  isLaunchSettling = false,
  isTeamAlive?: boolean,
  isTeamProvisioning?: boolean,
  leadActivity?: LeadActivityState
): string {
  const keepLaunchSettlingVisuals = isTeamProvisioning === true || isLaunchSettling;
  if (isTeamAlive === false && !isTeamProvisioning) {
    return STATUS_DOT_COLORS.terminated;
  }
  if (spawnLaunchState === 'failed_to_start' || spawnStatus === 'error') {
    return SPAWN_DOT_COLORS.error;
  }
  if (spawnLaunchState === 'skipped_for_launch' || spawnStatus === 'skipped') {
    return SPAWN_DOT_COLORS.skipped;
  }
  if (spawnLaunchState === 'runtime_pending_permission') {
    return 'bg-amber-400 animate-pulse';
  }
  if (
    isLaunchStillStarting(spawnStatus, spawnLaunchState, runtimeAlive, keepLaunchSettlingVisuals)
  ) {
    return spawnStatus === 'spawning' ? SPAWN_DOT_COLORS.spawning : SPAWN_DOT_COLORS.waiting;
  }
  if (spawnLaunchState === 'runtime_pending_bootstrap' && spawnStatus === 'online') {
    return SPAWN_DOT_COLORS.online;
  }
  if (spawnStatus === 'waiting') {
    return SPAWN_DOT_COLORS.waiting;
  }
  if (spawnStatus === 'online') {
    return SPAWN_DOT_COLORS.online;
  }
  if (spawnStatus === 'offline' && isTeamProvisioning) {
    return SPAWN_DOT_COLORS.offline;
  }
  if (spawnStatus === 'spawning' && isTeamProvisioning) {
    return SPAWN_DOT_COLORS.spawning;
  }
  return getMemberDotClass(member, isTeamAlive, isTeamProvisioning, leadActivity);
}

/**
 * Returns presence label for a member during provisioning, respecting spawn status.
 */
export function getSpawnAwarePresenceLabel(
  member: ResolvedTeamMember,
  spawnStatus: MemberSpawnStatus | undefined,
  spawnLaunchState: MemberLaunchState | undefined,
  livenessSource: MemberSpawnLivenessSource | undefined,
  runtimeAlive: boolean | undefined,
  isLaunchSettling = false,
  isTeamAlive?: boolean,
  isTeamProvisioning?: boolean,
  leadActivity?: LeadActivityState
): string {
  const keepLaunchSettlingVisuals = isTeamProvisioning === true || isLaunchSettling;
  if (isTeamAlive === false && !isTeamProvisioning) {
    return 'offline';
  }
  if (spawnLaunchState === 'failed_to_start' || spawnStatus === 'error') {
    return SPAWN_PRESENCE_LABELS.error;
  }
  if (spawnLaunchState === 'skipped_for_launch' || spawnStatus === 'skipped') {
    return SPAWN_PRESENCE_LABELS.skipped;
  }
  if (spawnLaunchState === 'runtime_pending_permission') {
    return 'connecting';
  }
  if (
    isLaunchStillStarting(spawnStatus, spawnLaunchState, runtimeAlive, keepLaunchSettlingVisuals)
  ) {
    return 'starting';
  }
  if (spawnStatus === 'online' && keepLaunchSettlingVisuals) {
    return SPAWN_PRESENCE_LABELS.online;
  }
  if (spawnStatus === 'online' && livenessSource === 'process') {
    return 'online';
  }
  if (spawnStatus && isTeamProvisioning) {
    return SPAWN_PRESENCE_LABELS[spawnStatus];
  }
  return getPresenceLabel(member, isTeamAlive, isTeamProvisioning, leadActivity);
}

/**
 * Card container CSS classes based on spawn status (opacity + animation).
 * Used by MemberCard wrapper for fade-in transitions.
 */
export function getSpawnCardClass(
  spawnStatus: MemberSpawnStatus | undefined,
  spawnLaunchState?: MemberLaunchState,
  runtimeAlive?: boolean,
  isLaunchSettling = false,
  isTeamAlive?: boolean,
  isTeamProvisioning?: boolean
): string {
  const keepLaunchSettlingVisuals = isTeamProvisioning === true || isLaunchSettling;
  if (isTeamAlive === false && !isTeamProvisioning) {
    return '';
  }
  if (
    isLaunchStillStarting(spawnStatus, spawnLaunchState, runtimeAlive, keepLaunchSettlingVisuals)
  ) {
    return 'member-waiting-shimmer';
  }
  if (spawnLaunchState === 'skipped_for_launch' || spawnStatus === 'skipped') {
    return 'opacity-70';
  }
  if (spawnLaunchState === 'runtime_pending_permission') {
    return 'member-waiting-shimmer';
  }
  switch (spawnStatus) {
    case 'offline':
      return spawnLaunchState === 'starting' ? 'member-waiting-shimmer opacity-75' : 'opacity-40';
    case 'waiting':
      return 'member-waiting-shimmer';
    case 'spawning':
      return 'member-waiting-shimmer';
    case 'online':
      return 'animate-[member-fade-in_0.4s_ease-out]';
    case 'error':
      return 'opacity-80';
    default:
      return '';
  }
}

function formatRetryCountdown(ms: number): string {
  const totalSeconds = Math.max(1, Math.ceil(ms / 1000));
  if (totalSeconds < 60) {
    return `${totalSeconds}s`;
  }
  const minutes = Math.floor(totalSeconds / 60);
  if (minutes >= 60) {
    const hours = Math.floor(minutes / 60);
    const remainingMinutes = minutes % 60;
    return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;
  }
  const seconds = totalSeconds % 60;
  return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
}

function getRuntimeAdvisoryRetryRemainingMs(
  advisory: MemberRuntimeAdvisory,
  nowMs: number
): number | null {
  const retryUntilMs = advisory.retryUntil ? Date.parse(advisory.retryUntil) : Number.NaN;
  if (!Number.isFinite(retryUntilMs)) {
    return null;
  }
  const remainingMs = retryUntilMs - nowMs;
  return remainingMs > 0 ? remainingMs : null;
}

function isRetryTimedApiAdvisory(
  advisory: MemberRuntimeAdvisory,
  providerId: TeamProviderId | undefined
): boolean {
  return (
    advisory.kind === 'api_error' &&
    providerId === 'opencode' &&
    (advisory.reasonCode === 'quota_exhausted' || advisory.reasonCode === 'rate_limited')
  );
}

function formatRetryUntilUtc(value: string | undefined): string | null {
  const retryUntilMs = value ? Date.parse(value) : Number.NaN;
  if (!Number.isFinite(retryUntilMs)) {
    return null;
  }
  const date = new Date(retryUntilMs);
  const hours = String(date.getUTCHours()).padStart(2, '0');
  const minutes = String(date.getUTCMinutes()).padStart(2, '0');
  return `${hours}:${minutes} UTC`;
}

function appendRuntimeAdvisoryRetryHint(
  base: string,
  advisory: MemberRuntimeAdvisory,
  providerId: TeamProviderId | undefined
): string {
  if (!isRetryTimedApiAdvisory(advisory, providerId)) {
    return base;
  }
  const retryAt = formatRetryUntilUtc(advisory.retryUntil);
  if (!retryAt) {
    return base;
  }
  return `${base} Waiting for OpenCode retry or quota reset around ${retryAt}.`;
}

function getRuntimeAdvisoryProviderLabel(providerId: TeamProviderId | undefined): string | null {
  switch (providerId) {
    case 'anthropic':
      return 'Anthropic';
    case 'codex':
      return 'Codex';
    case 'gemini':
      return 'Gemini';
    case 'opencode':
      return 'OpenCode';
    default:
      return null;
  }
}

function appendRuntimeAdvisoryRawMessage(
  base: string,
  message: string | undefined,
  providerId?: TeamProviderId
): string {
  const trimmed = formatRuntimeAdvisoryDisplayMessage(message, providerId);
  if (trimmed === base) {
    return base;
  }
  return trimmed ? `${base}\n\n${trimmed}` : base;
}

const OPENCODE_SESSION_REFRESH_REASON_PATTERN =
  /\b(?:resolved_behavior_changed|opencode_app_mcp_transport_changed):[-a-z0-9._~/=]+->[-a-z0-9._~/=]+/i;
const OPENCODE_SESSION_REFRESH_FAILURE_PATTERN =
  // eslint-disable-next-line sonarjs/regex-complexity -- Keyword taxonomy is kept literal to preserve diagnostic behavior.
  /(?:^|[_\s:;./()-])(?:permission[_\s-]?denied|permission[_\s-]?blocked|access[_\s-]?denied|auth[_\s-]?unavailable|authentication[_\s-]?failed|unauthorized|forbidden|401|403|login[_\s-]?required|not\s+logged\s+in|missing\s+credentials?|invalid\s+credentials?|credentials?[_\s-]?required|credentials?[_\s-]?unavailable|no auth available|authorization|auth(?:entication)?(?:[_\s-]?(?:failed|unavailable))?|invalid api[_\s-]?key|api[_\s-]?key|does not have access|quota|rate[_\s-]?(?:limit|limited)|too many requests|429|model cooldown|cooling down|enospc|no space left|disk is full|capacity exceeded|quota exhausted|usage exceeded|free usage exceeded|key limit exceeded|total limit|insufficient credits|subscribe to go|error|failed|failure|timeout|timed\s+out|network|connection|unable\s+to\s+connect|connect\s+failed|econn[a-z_]*|enotfound|fetch[_\s-]?failed|connection[_\s-]?(?:refused|reset)|aborted|cancel(?:ed|led)|interrupted|service[_\s-]?unavailable|temporarily\s+unavailable|overloaded|visible[_\s-]?reply(?:[_\s-][a-z0-9]+)*|task[_\s-]?refs|relayofmessageid|relay[_\s-]?of[_\s-]?message[_\s-]?id|message[_\s-]?send|non[_\s-]?visible[_\s-]?tool(?:[_\s-][a-z0-9]+)*|protocol[_\s-]?proof)(?=$|[_\s:;./(),-])/i;
const OPENCODE_SESSION_REFRESH_ANY_REASON_PATTERN =
  /\b(?:resolved_behavior_changed|opencode_app_mcp_transport_changed):[-a-z0-9._~/=]+->[-a-z0-9._~/=]+/gi;
const OPENCODE_SESSION_REFRESH_SAFE_MARKER_STATE_PATTERN =
  /\b(?:not_observed|pending|prompt_not_indexed|responded_tool_call|responded_visible_message|responded_non_visible_tool|responded_plain_text|permission_blocked|tool_error|empty_assistant_turn|prompt_delivered_no_assistant_message|session_stale|session_error|reconcile_failed)\b/g;

function isRecoverableOpenCodeSessionRefreshMessage(message: string | undefined): boolean {
  const normalized = message?.trim().toLowerCase() ?? '';
  const refreshText = stripOpenCodeGenericApiErrorPrefix(normalized);
  const refreshMarkerText = refreshText.replace(/[.:\s-]+$/, '');
  if (
    refreshMarkerText === 'session_stale' ||
    refreshMarkerText === 'opencode session changed; refreshing the session before retry' ||
    refreshMarkerText === 'opencode session refresh scheduled after resolved behavior changed' ||
    refreshMarkerText === 'opencode_prompt_delivery_session_refresh_scheduled' ||
    refreshMarkerText === 'opencode_session_refresh_scheduled_after_resolved_behavior_changed' ||
    refreshMarkerText === 'opencode_session_stale_observe_scheduled_after_accepted_prompt'
  ) {
    return true;
  }
  if (!OPENCODE_SESSION_REFRESH_REASON_PATTERN.test(refreshText)) {
    return false;
  }
  const markerText = refreshText;
  if (hasOpenCodeSessionRefreshFailureConflict(markerText)) {
    return false;
  }
  const rawRemainder = markerText.replace(OPENCODE_SESSION_REFRESH_ANY_REASON_PATTERN, '');
  const remainder = rawRemainder.replace(/[().,;:\s-]+/g, '');
  if (remainder.length === 0) {
    return true;
  }
  const staleLogProjectionContext =
    normalized.includes('session is stale') ||
    normalized.includes('stored session is stale') ||
    normalized.includes('session reconcile skipped');
  return staleLogProjectionContext && isBenignOpenCodeSessionRefreshRemainder(rawRemainder);
}

function stripOpenCodeGenericApiErrorPrefix(message: string): string {
  return message.replace(/^opencode api error(?:[.:\s-]+|$)/i, '');
}

function isBenignOpenCodeSessionRefreshRemainder(rawRemainder: string): boolean {
  if (OPENCODE_SESSION_REFRESH_FAILURE_PATTERN.test(rawRemainder)) {
    return false;
  }
  const normalized = rawRemainder.replace(/[().,;:\s-]+/g, ' ').trim();
  return (
    normalized === 'opencode session is stale' ||
    normalized ===
      'opencode session is stale reading historical messages for log projection only' ||
    normalized === 'opencode session reconcile skipped because the stored session is stale' ||
    normalized === 'stored session is stale'
  );
}

function hasOpenCodeSessionRefreshFailureConflict(value: string): boolean {
  return OPENCODE_SESSION_REFRESH_FAILURE_PATTERN.test(
    value.replace(OPENCODE_SESSION_REFRESH_SAFE_MARKER_STATE_PATTERN, 'state')
  );
}

function canTreatAdvisoryAsOpenCodeSessionRefresh(
  advisory: MemberRuntimeAdvisory | undefined
): boolean {
  return (
    Boolean(advisory) &&
    (advisory?.reasonCode == null ||
      advisory.reasonCode === 'backend_error' ||
      advisory.reasonCode === 'unknown') &&
    isRecoverableOpenCodeSessionRefreshMessage(advisory?.message)
  );
}

function isOpenCodeRuntimeDeliveryAdvisoryMessage(message: string | undefined): boolean {
  const displayMessage = formatRuntimeAdvisoryDisplayMessage(message, 'opencode');
  return (
    displayMessage.startsWith('OpenCode runtime delivery') ||
    displayMessage.startsWith('OpenCode returned an empty assistant turn') ||
    displayMessage.startsWith('OpenCode accepted the prompt') ||
    displayMessage.startsWith('OpenCode bridge outcome unknown after timeout') ||
    displayMessage.startsWith('OpenCode responded, but did not create') ||
    displayMessage.startsWith('OpenCode created a reply without') ||
    displayMessage.startsWith('OpenCode used tools, but did not create')
  );
}

function formatRuntimeAdvisoryDisplayMessage(
  message: string | undefined,
  providerId?: TeamProviderId
): string {
  const trimmed = message?.trim();
  if (!trimmed) {
    return '';
  }
  if (trimmed === 'empty_assistant_turn') {
    return 'OpenCode returned an empty assistant turn.';
  }
  if (trimmed === 'prompt_delivered_no_assistant_message') {
    return 'OpenCode accepted the prompt, but no assistant turn was recorded.';
  }
  if (trimmed === 'opencode_prompt_acceptance_unknown_after_bridge_timeout') {
    return OPENCODE_BRIDGE_OUTCOME_UNKNOWN_AFTER_TIMEOUT_MESSAGE;
  }
  if (providerId === 'opencode' && isRecoverableOpenCodeSessionRefreshMessage(trimmed)) {
    return 'OpenCode session changed; refreshing the session before retry.';
  }
  if (
    trimmed === 'visible_reply_still_required' ||
    trimmed === 'visible_reply_ack_only_still_requires_answer' ||
    trimmed === 'plain_text_ack_only_still_requires_answer'
  ) {
    return 'OpenCode responded, but did not create a visible message_send reply.';
  }
  if (
    trimmed === 'visible_reply_destination_not_found_yet' ||
    trimmed === 'visible_reply_missing_relayOfMessageId'
  ) {
    return 'OpenCode created a reply without the required relayOfMessageId correlation.';
  }
  if (trimmed === 'visible_reply_missing_task_refs') {
    return 'OpenCode created a reply without the required taskRefs metadata.';
  }
  if (trimmed === 'visible_reply_missing_task_refs_after_merge') {
    return 'OpenCode created a reply without the required taskRefs metadata.';
  }
  if (trimmed === 'visible_reply_task_refs_merge_failed') {
    return 'OpenCode created a reply without the required taskRefs metadata, and the app could not attach it automatically.';
  }
  if (trimmed === 'non_visible_tool_without_task_progress') {
    return 'OpenCode used tools, but did not create a visible reply or task progress proof.';
  }
  if (
    trimmed.startsWith(
      'OpenCode bootstrap MCP did not complete required tools before assistant response:'
    )
  ) {
    return 'OpenCode runtime delivery did not complete.';
  }
  return trimmed;
}

function formatRuntimeAdvisoryBaseLabel(
  advisory: MemberRuntimeAdvisory,
  providerId: TeamProviderId | undefined
): string {
  const providerLabel = getRuntimeAdvisoryProviderLabel(providerId);
  if (advisory.kind === 'api_error') {
    if (providerId === 'opencode' && canTreatAdvisoryAsOpenCodeSessionRefresh(advisory)) {
      return 'OpenCode session refresh';
    }
    switch (advisory.reasonCode) {
      case 'quota_exhausted':
        return providerLabel ? `${providerLabel} quota error` : 'Quota error';
      case 'rate_limited':
        return providerLabel ? `${providerLabel} rate limit` : 'Rate limit';
      case 'auth_error':
        return providerLabel ? `${providerLabel} auth error` : 'Auth error';
      case 'codex_native_timeout':
        return 'Codex native timeout';
      case 'network_error':
        return 'Network error';
      case 'filesystem_error':
        return 'Disk space error';
      case 'provider_overloaded':
        return providerLabel ? `${providerLabel} overload` : 'Provider overload';
      case 'protocol_proof_missing':
        return providerId === 'opencode' ? 'OpenCode proof missing' : 'Protocol proof missing';
      case 'backend_error':
      case 'unknown':
        if (
          providerId === 'opencode' &&
          isOpenCodeRuntimeDeliveryAdvisoryMessage(advisory.message)
        ) {
          return 'OpenCode delivery error';
        }
        return providerLabel ? `${providerLabel} API error` : 'API error';
      default:
        return 'API error';
    }
  }

  switch (advisory.reasonCode) {
    case 'quota_exhausted':
      return providerLabel ? `${providerLabel} quota retry` : 'Quota retry';
    case 'rate_limited':
      return providerLabel ? `${providerLabel} rate limit` : 'Rate limit retry';
    case 'auth_error':
      return providerLabel ? `${providerLabel} auth retry` : 'Auth retry';
    case 'codex_native_timeout':
      return 'Codex native retry';
    case 'network_error':
      return 'Network retry';
    case 'filesystem_error':
      return 'Disk space retry';
    case 'provider_overloaded':
      return providerLabel ? `${providerLabel} overload retry` : 'Provider overload retry';
    case 'protocol_proof_missing':
      return providerId === 'opencode' ? 'OpenCode proof missing' : 'Protocol proof missing';
    case 'backend_error':
    case 'unknown':
      return 'Provider retry';
    default:
      return 'retrying now';
  }
}

function formatRuntimeAdvisoryTitle(
  advisory: MemberRuntimeAdvisory,
  providerId: TeamProviderId | undefined
): string {
  const providerLabel = getRuntimeAdvisoryProviderLabel(providerId);
  if (advisory.kind === 'api_error') {
    if (providerId === 'opencode' && canTreatAdvisoryAsOpenCodeSessionRefresh(advisory)) {
      return appendRuntimeAdvisoryRawMessage(
        'OpenCode session changed; refreshing the session before retry.',
        advisory.message,
        providerId
      );
    }
    switch (advisory.reasonCode) {
      case 'quota_exhausted':
        return appendRuntimeAdvisoryRawMessage(
          appendRuntimeAdvisoryRetryHint(
            `${providerLabel ?? 'Provider'} quota exhausted.`,
            advisory,
            providerId
          ),
          advisory.message,
          providerId
        );
      case 'rate_limited':
        return appendRuntimeAdvisoryRawMessage(
          appendRuntimeAdvisoryRetryHint(
            `${providerLabel ?? 'Provider'} rate limited the request.`,
            advisory,
            providerId
          ),
          advisory.message,
          providerId
        );
      case 'auth_error':
        return appendRuntimeAdvisoryRawMessage(
          `${providerLabel ?? 'Provider'} authentication error.`,
          advisory.message,
          providerId
        );
      case 'codex_native_timeout':
        return appendRuntimeAdvisoryRawMessage(
          'Codex native mailbox turn timed out. The runtime stopped this turn after its watchdog limit; it was not an automatic SDK retry.',
          advisory.message,
          providerId
        );
      case 'network_error':
        return appendRuntimeAdvisoryRawMessage(
          'Network or connectivity error.',
          advisory.message,
          providerId
        );
      case 'filesystem_error':
        return appendRuntimeAdvisoryRawMessage(
          'Local disk is full or unavailable.',
          advisory.message,
          providerId
        );
      case 'provider_overloaded':
        return appendRuntimeAdvisoryRawMessage(
          'Provider is temporarily overloaded.',
          advisory.message,
          providerId
        );
      case 'protocol_proof_missing':
        return appendRuntimeAdvisoryRawMessage(
          providerId === 'opencode'
            ? 'OpenCode delivery completed without required visible/progress proof.'
            : 'Runtime delivery completed without required protocol proof.',
          advisory.message,
          providerId
        );
      case 'backend_error':
      case 'unknown':
        if (
          providerId === 'opencode' &&
          isOpenCodeRuntimeDeliveryAdvisoryMessage(advisory.message)
        ) {
          return appendRuntimeAdvisoryRawMessage(
            'OpenCode runtime delivery error.',
            advisory.message,
            providerId
          );
        }
        return appendRuntimeAdvisoryRawMessage(
          `${providerLabel ?? 'Provider'} API error.`,
          advisory.message,
          providerId
        );
      default:
        return advisory.message?.trim() || 'Provider API error.';
    }
  }

  switch (advisory.reasonCode) {
    case 'quota_exhausted':
      return appendRuntimeAdvisoryRawMessage(
        `${providerLabel ?? 'Provider'} quota exhausted. SDK is retrying automatically.`,
        advisory.message,
        providerId
      );
    case 'rate_limited':
      return appendRuntimeAdvisoryRawMessage(
        `${providerLabel ?? 'Provider'} rate limited the request. SDK is retrying automatically.`,
        advisory.message,
        providerId
      );
    case 'auth_error':
      return appendRuntimeAdvisoryRawMessage(
        `${providerLabel ?? 'Provider'} authentication issue. SDK is retrying automatically.`,
        advisory.message,
        providerId
      );
    case 'codex_native_timeout':
      return appendRuntimeAdvisoryRawMessage(
        'Codex native mailbox turn timed out. A retry window was reported by the runtime.',
        advisory.message,
        providerId
      );
    case 'network_error':
      return appendRuntimeAdvisoryRawMessage(
        'Network or connectivity issue. SDK is retrying automatically.',
        advisory.message,
        providerId
      );
    case 'filesystem_error':
      return appendRuntimeAdvisoryRawMessage(
        'Local disk is full or unavailable. SDK is retrying automatically.',
        advisory.message,
        providerId
      );
    case 'provider_overloaded':
      return appendRuntimeAdvisoryRawMessage(
        'Provider is temporarily overloaded. SDK is retrying automatically.',
        advisory.message,
        providerId
      );
    case 'protocol_proof_missing':
      return appendRuntimeAdvisoryRawMessage(
        providerId === 'opencode'
          ? 'OpenCode delivery is waiting for required visible/progress proof.'
          : 'Runtime delivery is waiting for required protocol proof.',
        advisory.message,
        providerId
      );
    case 'backend_error':
    case 'unknown':
      return appendRuntimeAdvisoryRawMessage(
        'The SDK is retrying this request after a provider or backend error.',
        advisory.message,
        providerId
      );
    default:
      return (
        advisory.message?.trim() ||
        'The SDK is retrying this request after a provider or backend error.'
      );
  }
}

export function getMemberRuntimeAdvisoryLabel(
  advisory: MemberRuntimeAdvisory | undefined,
  providerId?: TeamProviderId,
  nowMs = Date.now()
): string | null {
  if (!advisory) {
    return null;
  }
  const baseLabel = formatRuntimeAdvisoryBaseLabel(advisory, providerId);
  const remainingMs = getRuntimeAdvisoryRetryRemainingMs(advisory, nowMs);
  if (advisory.kind === 'api_error') {
    if (remainingMs && isRetryTimedApiAdvisory(advisory, providerId)) {
      return `${baseLabel} · retry ${formatRetryCountdown(remainingMs)}`;
    }
    return baseLabel;
  }
  if (advisory.kind !== 'sdk_retrying') {
    return null;
  }
  if (!remainingMs) {
    return baseLabel;
  }
  return `${baseLabel} · ${formatRetryCountdown(remainingMs)}`;
}

export function getMemberRuntimeAdvisoryTitle(
  advisory: MemberRuntimeAdvisory | undefined,
  providerId?: TeamProviderId
): string | undefined {
  if (!advisory || (advisory.kind !== 'sdk_retrying' && advisory.kind !== 'api_error')) {
    return undefined;
  }
  return formatRuntimeAdvisoryTitle(advisory, providerId);
}

export function getMemberRuntimeAdvisoryTone(
  advisory: MemberRuntimeAdvisory | undefined,
  providerId?: TeamProviderId
): 'error' | 'warning' | null {
  if (!advisory) {
    return null;
  }
  if (providerId === 'opencode' && canTreatAdvisoryAsOpenCodeSessionRefresh(advisory)) {
    return 'warning';
  }
  if (advisory.reasonCode === 'protocol_proof_missing') {
    return 'warning';
  }
  return advisory.kind === 'api_error' ? 'error' : 'warning';
}

export function getLaunchAwarePresenceLabel(
  member: ResolvedTeamMember,
  spawnStatus: MemberSpawnStatus | undefined,
  spawnLaunchState: MemberLaunchState | undefined,
  livenessSource: MemberSpawnLivenessSource | undefined,
  runtimeAlive: boolean | undefined,
  runtimeAdvisory: MemberRuntimeAdvisory | undefined,
  isLaunchSettling = false,
  isTeamAlive?: boolean,
  isTeamProvisioning?: boolean,
  leadActivity?: LeadActivityState
): string {
  const basePresenceLabel = getSpawnAwarePresenceLabel(
    member,
    spawnStatus,
    spawnLaunchState,
    livenessSource,
    runtimeAlive,
    isLaunchSettling,
    isTeamAlive,
    isTeamProvisioning,
    leadActivity
  );
  if (
    basePresenceLabel === 'starting' ||
    basePresenceLabel === 'connecting' ||
    basePresenceLabel === 'spawn failed' ||
    basePresenceLabel === 'skipped' ||
    basePresenceLabel === 'offline' ||
    basePresenceLabel === 'terminated'
  ) {
    return basePresenceLabel;
  }
  const advisoryLabel = getMemberRuntimeAdvisoryLabel(runtimeAdvisory, member.providerId);
  return advisoryLabel ?? basePresenceLabel;
}

export type MemberLaunchVisualState =
  | 'queued'
  | 'waiting'
  | 'spawning'
  | 'starting_stale'
  | 'permission_pending'
  | 'bootstrap_stalled'
  | 'runtime_pending'
  | 'shell_only'
  | 'runtime_candidate'
  | 'registered_only'
  | 'stale_runtime'
  | 'settling'
  | 'error'
  | 'skipped'
  | null;

export interface MemberLaunchPresentation {
  presenceLabel: string;
  dotClass: string;
  cardClass: string;
  runtimeAdvisoryLabel: string | null;
  runtimeAdvisoryTitle?: string;
  runtimeAdvisoryTone: 'error' | 'warning' | null;
  launchVisualState: MemberLaunchVisualState;
  launchStatusLabel: string | null;
  spawnBadgeLabel: string | null;
}

export function getMemberLaunchStatusLabel(visualState: MemberLaunchVisualState): string | null {
  switch (visualState) {
    case 'queued':
      return 'queued';
    case 'waiting':
      return 'waiting to start';
    case 'spawning':
      return 'starting';
    case 'starting_stale':
      return 'starting stale';
    case 'permission_pending':
      return 'awaiting permission';
    case 'bootstrap_stalled':
      return 'bootstrap stalled';
    case 'runtime_pending':
      return 'waiting for bootstrap';
    case 'shell_only':
      return 'shell only';
    case 'runtime_candidate':
      return 'bootstrap unconfirmed';
    case 'registered_only':
      return 'registered';
    case 'stale_runtime':
      return 'stale runtime';
    case 'settling':
      return 'joining team';
    case 'error':
      return 'failed';
    case 'skipped':
      return 'skipped';
    default:
      return null;
  }
}

function getLaunchVisualStateDotClass(visualState: MemberLaunchVisualState): string | null {
  switch (visualState) {
    case 'queued':
      return SPAWN_DOT_COLORS.waiting;
    case 'permission_pending':
    case 'bootstrap_stalled':
    case 'runtime_pending':
    case 'runtime_candidate':
      return 'bg-amber-400 animate-pulse';
    case 'starting_stale':
      return 'bg-amber-400';
    case 'registered_only':
      return STATUS_DOT_COLORS.terminated;
    case 'shell_only':
      return 'bg-amber-400';
    case 'stale_runtime':
      return STATUS_DOT_COLORS.terminated;
    default:
      return null;
  }
}

function getCurrentRuntimeOfflineVisualState(
  member: ResolvedTeamMember,
  runtimeEntry: TeamAgentRuntimeEntry | undefined,
  spawnStatus: MemberSpawnStatus | undefined,
  spawnLaunchState: MemberLaunchState | undefined,
  spawnRuntimeAlive: boolean | undefined,
  spawnBootstrapConfirmed: boolean | undefined,
  isTeamProvisioning: boolean | undefined
): MemberLaunchVisualState {
  // The team lead's runtime is tracked via config.leadSessionId, not as a
  // spawned runtime process.  In the OpenCode adapter path,
  // buildTeamAgentRuntimeSnapshot creates a synthetic runtime entry for the
  // lead with alive:false (no CLI child pid) and no livenessKind — which the
  // checks below would classify as stale_runtime.  Skip lead entries that
  // carry the lead backend marker so every team doesn't show the lead as
  // "stale-runtime" permanently.
  if (isLeadMember(member) && runtimeEntry?.backendType === 'lead') {
    return null;
  }
  if (runtimeEntry?.livenessKind === 'registered_only') {
    return 'registered_only';
  }
  if (
    runtimeEntry?.livenessKind === 'stale_metadata' ||
    runtimeEntry?.livenessKind === 'not_found'
  ) {
    return 'stale_runtime';
  }
  if (
    runtimeEntry?.alive === false &&
    (runtimeEntry.livenessKind == null ||
      runtimeEntry.livenessKind === 'runtime_process' ||
      runtimeEntry.livenessKind === 'confirmed_bootstrap')
  ) {
    return 'stale_runtime';
  }
  if (
    spawnRuntimeAlive === false &&
    (spawnStatus === 'online' || spawnLaunchState === 'confirmed_alive')
  ) {
    return 'stale_runtime';
  }
  if (
    shouldTreatCodexNativeRuntimeAsOffline({
      member,
      runtimeEntry,
      spawnStatus,
      spawnLaunchState,
      spawnRuntimeAlive,
      spawnBootstrapConfirmed,
      isTeamProvisioning,
    })
  ) {
    return 'stale_runtime';
  }
  return null;
}

function hasStoppedRuntimeLivenessKind(
  livenessKind: TeamAgentRuntimeEntry['livenessKind'] | undefined
): boolean {
  return (
    livenessKind === 'not_found' ||
    livenessKind === 'registered_only' ||
    livenessKind === 'shell_only' ||
    livenessKind === 'stale_metadata'
  );
}

function isCodexNativeProcessTeammate(member: ResolvedTeamMember): boolean {
  if (isLeadMember(member)) {
    return false;
  }
  return (
    member.providerId === 'codex' &&
    (member.providerBackendId == null || member.providerBackendId === 'codex-native')
  );
}

function hasLiveRuntimeProcessEvidence(runtimeEntry: TeamAgentRuntimeEntry | undefined): boolean {
  return runtimeEntry?.alive === true && runtimeEntry.livenessKind === 'runtime_process';
}

function hasSpawnRuntimeLiveClaim({
  spawnStatus,
  spawnLaunchState,
  spawnRuntimeAlive,
  spawnBootstrapConfirmed,
}: {
  spawnStatus?: MemberSpawnStatus;
  spawnLaunchState?: MemberLaunchState;
  spawnRuntimeAlive?: boolean;
  spawnBootstrapConfirmed?: boolean;
}): boolean {
  return (
    spawnStatus === 'online' ||
    spawnLaunchState === 'confirmed_alive' ||
    spawnRuntimeAlive === true ||
    spawnBootstrapConfirmed === true
  );
}

function shouldTreatCodexNativeRuntimeAsOffline({
  member,
  runtimeEntry,
  spawnStatus,
  spawnLaunchState,
  spawnRuntimeAlive,
  spawnBootstrapConfirmed,
  isTeamProvisioning,
}: {
  member: ResolvedTeamMember;
  runtimeEntry?: TeamAgentRuntimeEntry;
  spawnStatus?: MemberSpawnStatus;
  spawnLaunchState?: MemberLaunchState;
  spawnRuntimeAlive?: boolean;
  spawnBootstrapConfirmed?: boolean;
  isTeamProvisioning?: boolean;
}): boolean {
  if (!isCodexNativeProcessTeammate(member)) {
    return false;
  }
  if (
    spawnLaunchState === 'starting' ||
    spawnLaunchState === 'runtime_pending_bootstrap' ||
    spawnLaunchState === 'runtime_pending_permission'
  ) {
    return false;
  }
  if (hasLiveRuntimeProcessEvidence(runtimeEntry)) {
    return false;
  }
  if (
    isTeamProvisioning === true &&
    runtimeEntry == null &&
    !hasSpawnRuntimeLiveClaim({
      spawnStatus,
      spawnLaunchState,
      spawnRuntimeAlive,
      spawnBootstrapConfirmed,
    })
  ) {
    return false;
  }
  return (
    runtimeEntry != null ||
    hasSpawnRuntimeLiveClaim({
      spawnStatus,
      spawnLaunchState,
      spawnRuntimeAlive,
      spawnBootstrapConfirmed,
    }) ||
    spawnStatus == null
  );
}

export function shouldDisplayMemberCurrentTask({
  member,
  isTeamAlive,
  spawnStatus,
  spawnLaunchState,
  spawnRuntimeAlive,
  spawnEntry,
  runtimeEntry,
}: {
  member: ResolvedTeamMember;
  isTeamAlive?: boolean;
  spawnStatus?: MemberSpawnStatus;
  spawnLaunchState?: MemberLaunchState;
  spawnRuntimeAlive?: boolean;
  spawnEntry?: MemberSpawnStatusEntry;
  runtimeEntry?: TeamAgentRuntimeEntry;
}): boolean {
  const bootstrapConfirmedProvisionedButNotAlive =
    isBootstrapConfirmedProvisionedButNotAliveFailure(spawnEntry);
  const unsafeProvisionedButNotAliveEvidence =
    bootstrapConfirmedProvisionedButNotAlive &&
    hasUnsafeProvisionedButNotAliveRuntimeEvidenceWithSpawnContext(spawnEntry, runtimeEntry);
  const useBootstrapConfirmedVisualState =
    bootstrapConfirmedProvisionedButNotAlive && !unsafeProvisionedButNotAliveEvidence;
  const effectiveSpawnStatus = useBootstrapConfirmedVisualState ? 'online' : spawnStatus;
  const effectiveSpawnLaunchState = useBootstrapConfirmedVisualState
    ? 'confirmed_alive'
    : spawnLaunchState;
  const effectiveSpawnRuntimeAlive = useBootstrapConfirmedVisualState ? true : spawnRuntimeAlive;
  if (member.removedAt || member.status === 'terminated') {
    return false;
  }
  if (isTeamAlive === false) {
    return false;
  }
  if (
    effectiveSpawnStatus === 'offline' ||
    effectiveSpawnStatus === 'error' ||
    effectiveSpawnStatus === 'skipped'
  ) {
    return false;
  }
  if (
    effectiveSpawnLaunchState === 'failed_to_start' ||
    effectiveSpawnLaunchState === 'skipped_for_launch' ||
    effectiveSpawnLaunchState === 'runtime_pending_permission'
  ) {
    return false;
  }
  if (
    !useBootstrapConfirmedVisualState &&
    (runtimeEntry?.livenessKind === 'shell_only' ||
      spawnEntry?.livenessKind === 'shell_only' ||
      runtimeEntry?.livenessKind === 'registered_only' ||
      spawnEntry?.livenessKind === 'registered_only' ||
      runtimeEntry?.livenessKind === 'stale_metadata' ||
      spawnEntry?.livenessKind === 'stale_metadata' ||
      runtimeEntry?.livenessKind === 'not_found' ||
      spawnEntry?.livenessKind === 'not_found')
  ) {
    return false;
  }
  if (runtimeEntry?.runtimeDiagnosticSeverity === 'error') {
    return false;
  }
  if (spawnEntry?.runtimeDiagnosticSeverity === 'error') {
    return false;
  }
  if (runtimeEntry?.alive === false && !useBootstrapConfirmedVisualState) {
    return false;
  }
  if (effectiveSpawnRuntimeAlive === false) {
    return false;
  }
  if (isCodexNativeProcessTeammate(member) && !hasLiveRuntimeProcessEvidence(runtimeEntry)) {
    return false;
  }
  return true;
}

function isQueuedOpenCodeLaunch(
  member: ResolvedTeamMember,
  spawnStatus: MemberSpawnStatus | undefined,
  spawnLaunchState: MemberLaunchState | undefined,
  runtimeEntry: TeamAgentRuntimeEntry | undefined,
  isLaunchSettling: boolean,
  isTeamProvisioning: boolean | undefined
): boolean {
  if (member.providerId !== 'opencode') {
    return false;
  }
  if (isTeamProvisioning !== true && !isLaunchSettling) {
    return false;
  }
  if (spawnStatus !== 'waiting' || spawnLaunchState !== 'starting') {
    return false;
  }

  // Only label lanes as queued before runtime evidence appears. Once the
  // backend has any liveness signal, show the exact runtime state instead.
  return runtimeEntry?.livenessKind == null;
}

function hasElapsedSinceIso(
  value: string | undefined,
  thresholdMs: number,
  nowMs: number
): boolean {
  if (!value) {
    return false;
  }
  const parsed = Date.parse(value);
  return Number.isFinite(parsed) && nowMs - parsed >= thresholdMs;
}

export function isMemberStartingStale({
  spawnStatus,
  spawnLaunchState,
  spawnFirstSpawnAcceptedAt,
  spawnUpdatedAt,
  nowMs = Date.now(),
}: {
  spawnStatus?: MemberSpawnStatus;
  spawnLaunchState?: MemberLaunchState;
  spawnFirstSpawnAcceptedAt?: string;
  spawnUpdatedAt?: string;
  nowMs?: number;
}): boolean {
  if (
    spawnLaunchState === 'failed_to_start' ||
    spawnLaunchState === 'confirmed_alive' ||
    spawnLaunchState === 'skipped_for_launch' ||
    spawnLaunchState === 'runtime_pending_permission' ||
    spawnStatus === 'error' ||
    spawnStatus === 'online' ||
    spawnStatus === 'skipped'
  ) {
    return false;
  }
  if (spawnLaunchState !== 'starting' && spawnStatus !== 'waiting' && spawnStatus !== 'spawning') {
    return false;
  }

  return hasElapsedSinceIso(
    spawnFirstSpawnAcceptedAt ?? spawnUpdatedAt,
    MEMBER_STARTING_STALE_AFTER_MS,
    nowMs
  );
}

function hasBootstrapStallDiagnostic(value: string | undefined): boolean {
  const normalized = value?.trim().toLowerCase() ?? '';
  return (
    normalized.includes('no bootstrap check-in') ||
    normalized.includes('bootstrap is unconfirmed') ||
    normalized.includes('bootstrap unconfirmed')
  );
}

export function isOpenCodeRelaunchActionable({
  member,
  spawnEntry,
  runtimeEntry,
  nowMs = Date.now(),
}: {
  member: ResolvedTeamMember;
  spawnEntry?: MemberSpawnStatusEntry;
  runtimeEntry?: TeamAgentRuntimeEntry;
  nowMs?: number;
}): boolean {
  if (member.providerId !== 'opencode' || isLeadMember(member) || member.removedAt) {
    return false;
  }
  if (spawnEntry?.launchState === 'starting' || spawnEntry?.status === 'spawning') {
    return false;
  }
  if (spawnEntry?.launchState === 'runtime_pending_permission') {
    return false;
  }
  if (!spawnEntry) {
    const runtimeDiagnosticIsStuck = hasBootstrapStallDiagnostic(runtimeEntry?.runtimeDiagnostic);
    return (
      runtimeDiagnosticIsStuck ||
      runtimeEntry?.livenessKind === 'registered_only' ||
      runtimeEntry?.livenessKind === 'stale_metadata'
    );
  }
  if (isBootstrapConfirmedProvisionedButNotAliveFailure(spawnEntry)) {
    return hasUnsafeProvisionedButNotAliveRuntimeEvidenceWithSpawnContext(spawnEntry, runtimeEntry);
  }
  if (
    spawnEntry?.launchState === 'failed_to_start' ||
    spawnEntry?.launchState === 'skipped_for_launch' ||
    spawnEntry?.status === 'error' ||
    spawnEntry?.status === 'skipped'
  ) {
    return true;
  }

  const livenessKind = runtimeEntry?.livenessKind ?? spawnEntry?.livenessKind;
  const acceptedSpawnGraceElapsed = hasElapsedSinceIso(
    spawnEntry?.firstSpawnAcceptedAt,
    OPENCODE_RUNTIME_CANDIDATE_RELAUNCH_GRACE_MS,
    nowMs
  );
  const hasExplicitBootstrapStall =
    spawnEntry?.bootstrapStalled === true ||
    hasBootstrapStallDiagnostic(spawnEntry?.runtimeDiagnostic) ||
    hasBootstrapStallDiagnostic(runtimeEntry?.runtimeDiagnostic);
  const launchIsNoLongerFresh =
    spawnEntry.launchState === 'confirmed_alive' ||
    spawnEntry.status === 'online' ||
    acceptedSpawnGraceElapsed ||
    hasExplicitBootstrapStall;

  if (
    livenessKind === 'registered_only' ||
    livenessKind === 'stale_metadata' ||
    livenessKind === 'not_found'
  ) {
    return launchIsNoLongerFresh;
  }
  if (livenessKind === 'runtime_process') {
    return hasExplicitBootstrapStall;
  }
  if (livenessKind !== 'runtime_process_candidate') {
    return false;
  }

  return acceptedSpawnGraceElapsed || hasExplicitBootstrapStall;
}

export function buildMemberLaunchPresentation({
  member,
  spawnStatus,
  spawnLaunchState,
  spawnLivenessSource,
  spawnRuntimeAlive,
  spawnBootstrapConfirmed,
  spawnBootstrapStalled,
  spawnAgentToolAccepted,
  spawnHardFailure,
  spawnHardFailureReason,
  spawnError,
  spawnRuntimeDiagnostic,
  spawnLivenessKind,
  spawnRuntimeDiagnosticSeverity,
  spawnFirstSpawnAcceptedAt,
  spawnUpdatedAt,
  runtimeAdvisory,
  runtimeEntry,
  isLaunchSettling = false,
  isTeamAlive,
  isTeamProvisioning,
  leadActivity,
  nowMs,
}: {
  member: ResolvedTeamMember;
  spawnStatus: MemberSpawnStatus | undefined;
  spawnLaunchState: MemberLaunchState | undefined;
  spawnLivenessSource: MemberSpawnLivenessSource | undefined;
  spawnRuntimeAlive: boolean | undefined;
  spawnBootstrapConfirmed?: boolean;
  spawnBootstrapStalled?: boolean;
  spawnAgentToolAccepted?: boolean;
  spawnHardFailure?: boolean;
  spawnHardFailureReason?: string;
  spawnError?: string;
  spawnRuntimeDiagnostic?: string;
  spawnLivenessKind?: TeamAgentRuntimeEntry['livenessKind'];
  spawnRuntimeDiagnosticSeverity?: TeamAgentRuntimeDiagnosticSeverity;
  spawnFirstSpawnAcceptedAt?: string;
  spawnUpdatedAt?: string;
  runtimeAdvisory: MemberRuntimeAdvisory | undefined;
  runtimeEntry?: TeamAgentRuntimeEntry;
  isLaunchSettling?: boolean;
  isTeamAlive?: boolean;
  isTeamProvisioning?: boolean;
  leadActivity?: LeadActivityState;
  nowMs?: number;
}): MemberLaunchPresentation {
  const bootstrapConfirmedProvisionedButNotAlive =
    isBootstrapConfirmedProvisionedButNotAliveFailure({
      status: spawnStatus,
      launchState: spawnLaunchState,
      hardFailure: spawnHardFailure,
      hardFailureReason: spawnHardFailureReason,
      error: spawnError,
      runtimeDiagnostic: spawnRuntimeDiagnostic,
      runtimeDiagnosticSeverity: spawnRuntimeDiagnosticSeverity,
      bootstrapConfirmed: spawnBootstrapConfirmed,
      livenessKind: spawnLivenessKind ?? runtimeEntry?.livenessKind,
    });
  const hasSpawnRuntimeErrorDiagnostic = spawnRuntimeDiagnosticSeverity === 'error';
  const hasRuntimeErrorDiagnostic = runtimeEntry?.runtimeDiagnosticSeverity === 'error';
  const hasUnsafeProvisionedButNotAliveEvidence =
    bootstrapConfirmedProvisionedButNotAlive &&
    hasUnsafeProvisionedButNotAliveRuntimeEvidenceWithSpawnContext(
      {
        status: spawnStatus,
        launchState: spawnLaunchState,
        hardFailure: spawnHardFailure,
        hardFailureReason: spawnHardFailureReason,
        error: spawnError,
        runtimeDiagnostic: spawnRuntimeDiagnostic,
        runtimeDiagnosticSeverity: spawnRuntimeDiagnosticSeverity,
        bootstrapConfirmed: spawnBootstrapConfirmed,
        livenessKind: spawnLivenessKind,
      },
      runtimeEntry
    );
  const allowBootstrapConfirmedVisualPromotion =
    bootstrapConfirmedProvisionedButNotAlive &&
    !hasSpawnRuntimeErrorDiagnostic &&
    !hasRuntimeErrorDiagnostic &&
    !hasUnsafeProvisionedButNotAliveEvidence;
  const useBootstrapConfirmedRuntimeAlive =
    allowBootstrapConfirmedVisualPromotion && !hasRuntimeErrorDiagnostic;
  const suppressConfirmedLaunchRuntimeAlivePromotion =
    bootstrapConfirmedProvisionedButNotAlive && !useBootstrapConfirmedRuntimeAlive;
  const visualSpawnStatus = allowBootstrapConfirmedVisualPromotion ? 'online' : spawnStatus;
  const visualSpawnLaunchState = allowBootstrapConfirmedVisualPromotion
    ? 'confirmed_alive'
    : spawnLaunchState;
  const visualSpawnRuntimeAlive = useBootstrapConfirmedRuntimeAlive ? true : spawnRuntimeAlive;
  const visualSpawnBootstrapConfirmed = allowBootstrapConfirmedVisualPromotion
    ? true
    : spawnBootstrapConfirmed;
  const visualSpawnHardFailure = allowBootstrapConfirmedVisualPromotion ? false : spawnHardFailure;
  const visualSpawnLivenessKind = allowBootstrapConfirmedVisualPromotion
    ? 'confirmed_bootstrap'
    : spawnLivenessKind;
  const visualRuntimeEntry =
    useBootstrapConfirmedRuntimeAlive && runtimeEntry
      ? ({
          ...runtimeEntry,
          alive: true,
          livenessKind: 'confirmed_bootstrap',
        } satisfies TeamAgentRuntimeEntry)
      : runtimeEntry;
  const currentRuntimeOfflineVisualState = getCurrentRuntimeOfflineVisualState(
    member,
    visualRuntimeEntry,
    visualSpawnStatus,
    visualSpawnLaunchState,
    visualSpawnRuntimeAlive,
    visualSpawnBootstrapConfirmed,
    isTeamProvisioning
  );
  const hasConfirmedSpawnLaunch =
    visualSpawnLaunchState === 'confirmed_alive' && visualSpawnBootstrapConfirmed === true;
  const suppressOpenCodeAppMcpAdvisory = isHealthyOpenCodeAppMcpConnectivityAdvisory({
    providerId: member.providerId,
    runtimeAdvisory,
    spawnStatus: visualSpawnStatus,
    launchState: visualSpawnLaunchState,
    runtimeAlive: visualSpawnRuntimeAlive,
    bootstrapConfirmed: visualSpawnBootstrapConfirmed,
    agentToolAccepted: spawnAgentToolAccepted,
    hardFailure: visualSpawnHardFailure,
    livenessKind: visualSpawnLivenessKind ?? visualRuntimeEntry?.livenessKind,
    runtimeEntry: visualRuntimeEntry,
  });
  const displayRuntimeAdvisory = suppressOpenCodeAppMcpAdvisory ? undefined : runtimeAdvisory;
  const effectiveSpawnStatus =
    hasConfirmedSpawnLaunch &&
    currentRuntimeOfflineVisualState == null &&
    (visualSpawnStatus === 'waiting' || visualSpawnStatus === 'spawning')
      ? 'online'
      : visualSpawnStatus;
  const effectiveSpawnRuntimeAlive =
    currentRuntimeOfflineVisualState != null
      ? false
      : hasConfirmedSpawnLaunch && !suppressConfirmedLaunchRuntimeAlivePromotion
        ? true
        : visualSpawnRuntimeAlive;
  const presenceLabel = getLaunchAwarePresenceLabel(
    member,
    effectiveSpawnStatus,
    visualSpawnLaunchState,
    spawnLivenessSource,
    effectiveSpawnRuntimeAlive,
    displayRuntimeAdvisory,
    isLaunchSettling,
    isTeamAlive,
    isTeamProvisioning,
    leadActivity
  );
  const baseDotClass = getSpawnAwareDotClass(
    member,
    effectiveSpawnStatus,
    visualSpawnLaunchState,
    effectiveSpawnRuntimeAlive,
    isLaunchSettling,
    isTeamAlive,
    isTeamProvisioning,
    leadActivity
  );
  const cardClass = getSpawnCardClass(
    effectiveSpawnStatus,
    visualSpawnLaunchState,
    effectiveSpawnRuntimeAlive,
    isLaunchSettling,
    isTeamAlive,
    isTeamProvisioning
  );
  const runtimeAdvisoryLabel = getMemberRuntimeAdvisoryLabel(
    displayRuntimeAdvisory,
    member.providerId
  );
  const runtimeAdvisoryTitle = getMemberRuntimeAdvisoryTitle(
    displayRuntimeAdvisory,
    member.providerId
  );
  const runtimeAdvisoryTone = getMemberRuntimeAdvisoryTone(
    displayRuntimeAdvisory,
    member.providerId
  );
  const keepLaunchSettlingVisuals = isTeamProvisioning === true || isLaunchSettling;
  const startingIsStale =
    !hasConfirmedSpawnLaunch &&
    isMemberStartingStale({
      spawnStatus: visualSpawnStatus,
      spawnLaunchState: visualSpawnLaunchState,
      spawnFirstSpawnAcceptedAt,
      spawnUpdatedAt,
      nowMs,
    });

  let launchVisualState: MemberLaunchVisualState = null;
  if (isTeamAlive !== false || isTeamProvisioning) {
    if (visualSpawnLaunchState === 'failed_to_start' || visualSpawnStatus === 'error') {
      launchVisualState = 'error';
    } else if (visualSpawnLaunchState === 'skipped_for_launch' || visualSpawnStatus === 'skipped') {
      launchVisualState = 'skipped';
    } else if (visualSpawnLaunchState === 'runtime_pending_permission') {
      launchVisualState = 'permission_pending';
    } else if (spawnBootstrapStalled === true) {
      launchVisualState = 'bootstrap_stalled';
    } else if (currentRuntimeOfflineVisualState != null) {
      launchVisualState = currentRuntimeOfflineVisualState;
    } else if (visualRuntimeEntry?.livenessKind === 'shell_only') {
      launchVisualState = 'shell_only';
    } else if (visualRuntimeEntry?.livenessKind === 'runtime_process_candidate') {
      launchVisualState = 'runtime_candidate';
    } else if (!hasConfirmedSpawnLaunch && startingIsStale) {
      launchVisualState = 'starting_stale';
    } else if (
      !hasConfirmedSpawnLaunch &&
      isQueuedOpenCodeLaunch(
        member,
        visualSpawnStatus,
        visualSpawnLaunchState,
        visualRuntimeEntry,
        isLaunchSettling,
        isTeamProvisioning
      )
    ) {
      launchVisualState = 'queued';
    } else if (
      !hasConfirmedSpawnLaunch &&
      isLaunchStillStarting(
        visualSpawnStatus,
        visualSpawnLaunchState,
        visualSpawnRuntimeAlive,
        keepLaunchSettlingVisuals
      )
    ) {
      launchVisualState = visualSpawnStatus === 'spawning' ? 'spawning' : 'waiting';
    } else if (
      !hasConfirmedSpawnLaunch &&
      visualSpawnLaunchState === 'runtime_pending_bootstrap' &&
      (visualRuntimeEntry?.livenessKind === 'runtime_process' ||
        (visualSpawnStatus === 'online' && visualSpawnRuntimeAlive === true))
    ) {
      launchVisualState = 'runtime_pending';
    } else if (isLaunchSettling && visualSpawnLaunchState === 'confirmed_alive') {
      launchVisualState = 'settling';
    }
  }

  const launchStatusLabel = getMemberLaunchStatusLabel(launchVisualState);
  const launchVisualStateDotClass = getLaunchVisualStateDotClass(launchVisualState);
  const shouldShowLaunchStatusAsPresence =
    launchVisualState === 'queued' ||
    launchVisualState === 'starting_stale' ||
    launchVisualState === 'permission_pending' ||
    launchVisualState === 'bootstrap_stalled' ||
    launchVisualState === 'runtime_pending' ||
    launchVisualState === 'shell_only' ||
    launchVisualState === 'runtime_candidate' ||
    launchVisualState === 'registered_only' ||
    launchVisualState === 'stale_runtime';
  const displayPresenceLabel =
    runtimeAdvisoryTone === 'error' && runtimeAdvisoryLabel
      ? runtimeAdvisoryLabel
      : shouldShowLaunchStatusAsPresence
        ? (launchStatusLabel ?? presenceLabel)
        : presenceLabel;
  const spawnBadgeLabel =
    effectiveSpawnStatus && effectiveSpawnStatus !== 'online'
      ? effectiveSpawnStatus === 'waiting' || effectiveSpawnStatus === 'spawning'
        ? startingIsStale
          ? 'starting stale'
          : 'starting'
        : effectiveSpawnStatus
      : null;

  return {
    presenceLabel: displayPresenceLabel,
    dotClass:
      runtimeAdvisoryTone === 'error'
        ? STATUS_DOT_COLORS.terminated
        : (launchVisualStateDotClass ?? baseDotClass),
    cardClass: launchVisualState === 'starting_stale' ? 'opacity-90' : cardClass,
    runtimeAdvisoryLabel,
    runtimeAdvisoryTitle,
    runtimeAdvisoryTone,
    launchVisualState,
    launchStatusLabel,
    spawnBadgeLabel,
  };
}

export const TASK_STATUS_STYLES: Record<TeamTaskStatus, { bg: string; text: string }> = {
  pending: { bg: 'bg-zinc-500/15', text: 'text-zinc-400' },
  in_progress: { bg: 'bg-blue-500/15', text: 'text-blue-400' },
  completed: { bg: 'bg-emerald-500/15', text: 'text-emerald-400' },
  deleted: { bg: 'bg-red-500/15', text: 'text-red-400' },
};

export const TASK_STATUS_LABELS: Record<TeamTaskStatus, string> = {
  pending: 'Pending',
  in_progress: 'In Progress',
  completed: 'Completed',
  deleted: 'Deleted',
};

interface MemberColorInput {
  name: string;
  color?: string;
  removedAt?: number | string | null;
  agentType?: string;
  role?: string;
}

interface MemberAvatarInput {
  name: string;
  removedAt?: number | string | null;
  agentType?: string;
}

/**
 * Build a consistent name→colorName map for all members.
 * Active members receive colors sequentially from MEMBER_COLOR_PALETTE,
 * which is pre-ordered for maximum visual contrast between consecutive entries.
 * If a member has a stored color that hasn't been assigned yet, it is used instead.
 * Maps "user" to a reserved color.
 */
export function buildMemberColorMap(members: MemberColorInput[]): Map<string, string> {
  return buildTeamMemberColorMap(members, { preferProvidedColors: true });
}

export function buildMemberAvatarMap(members: readonly MemberAvatarInput[]): Map<string, string> {
  const map = new Map<string, string>();
  const activeMembers = members.filter((member) => !member.removedAt);
  const leadMembers = activeMembers.filter((member) => isLeadMember(member));
  const teammateMembers = activeMembers.filter((member) => !isLeadMember(member));

  for (const [index, member] of leadMembers.entries()) {
    map.set(member.name, index === 0 ? LEAD_PARTICIPANT_AVATAR_URL : agentAvatarUrl(member.name));
  }

  for (const [index, member] of teammateMembers.entries()) {
    map.set(
      member.name,
      getParticipantAvatarUrlByIndex(1 + (index % (PARTICIPANT_AVATAR_URLS.length - 1)))
    );
  }

  for (const member of members) {
    if (!map.has(member.name)) {
      map.set(
        member.name,
        isLeadMember(member) ? LEAD_PARTICIPANT_AVATAR_URL : agentAvatarUrl(member.name)
      );
    }
  }

  map.set('user', agentAvatarUrl('user'));
  map.set('system', agentAvatarUrl('system'));

  return map;
}

export function resolveMemberAvatarUrl(
  member: MemberAvatarInput,
  avatarMap?: ReadonlyMap<string, string>,
  size = 64
): string {
  return (
    avatarMap?.get(member.name) ??
    (isLeadMember(member) ? LEAD_PARTICIPANT_AVATAR_URL : agentAvatarUrl(member.name, size))
  );
}

export const KANBAN_COLUMN_DISPLAY: Record<
  'review' | 'approved',
  { label: string; bg: string; text: string }
> = {
  review: { label: 'In Review', bg: 'bg-amber-500/15', text: 'text-amber-400' },
  approved: { label: 'Approved', bg: 'bg-emerald-500/15', text: 'text-emerald-400' },
};

export const REVIEW_STATE_DISPLAY: Record<
  Exclude<TeamReviewState, 'none'>,
  { label: string; bg: string; text: string }
> = {
  review: { label: 'In Review', bg: 'bg-amber-500/15', text: 'text-amber-400' },
  needsFix: { label: 'Needs Fixes', bg: 'bg-rose-500/15', text: 'text-rose-400' },
  approved: { label: 'Approved', bg: 'bg-emerald-500/15', text: 'text-emerald-400' },
};
