import type { SessionEntry } from "../../config/sessions.js";
import { buildAgentMainSessionKey } from "../../routing/session-key.js";
import { parseAgentSessionKey } from "../../sessions/session-key-utils.js";
import {
  deliveryContextFromSession,
  deliveryContextKey,
  normalizeDeliveryContext,
} from "../../utils/delivery-context.js";
import {
  INTERNAL_MESSAGE_CHANNEL,
  isDeliverableMessageChannel,
  normalizeMessageChannel,
} from "../../utils/message-channel.js";
import type { MsgContext } from "../templating.js";

export type LegacyMainDeliveryRetirement = {
  key: string;
  entry: SessionEntry;
};

function resolveSessionKeyChannelHint(sessionKey?: string): string | undefined {
  const parsed = parseAgentSessionKey(sessionKey);
  if (!parsed?.rest) {
    return undefined;
  }
  const head = parsed.rest.split(":")[0]?.trim().toLowerCase();
  if (!head || head === "main" || head === "cron" || head === "subagent" || head === "acp") {
    return undefined;
  }
  return normalizeMessageChannel(head);
}

function isExternalRoutingChannel(channel?: string): channel is string {
  return Boolean(
    channel && channel !== INTERNAL_MESSAGE_CHANNEL && isDeliverableMessageChannel(channel),
  );
}

export function resolveLastChannelRaw(params: {
  originatingChannelRaw?: string;
  persistedLastChannel?: string;
  sessionKey?: string;
}): string | undefined {
  const originatingChannel = normalizeMessageChannel(params.originatingChannelRaw);
  const persistedChannel = normalizeMessageChannel(params.persistedLastChannel);
  const sessionKeyChannelHint = resolveSessionKeyChannelHint(params.sessionKey);
  let resolved = params.originatingChannelRaw || params.persistedLastChannel;
  // Internal/non-deliverable sources should not overwrite previously known
  // external delivery routes (or explicit channel hints from the session key).
  if (!isExternalRoutingChannel(originatingChannel)) {
    if (isExternalRoutingChannel(persistedChannel)) {
      resolved = persistedChannel;
    } else if (isExternalRoutingChannel(sessionKeyChannelHint)) {
      resolved = sessionKeyChannelHint;
    }
  }
  return resolved;
}

export function resolveLastToRaw(params: {
  originatingChannelRaw?: string;
  originatingToRaw?: string;
  toRaw?: string;
  persistedLastTo?: string;
  persistedLastChannel?: string;
  sessionKey?: string;
}): string | undefined {
  const originatingChannel = normalizeMessageChannel(params.originatingChannelRaw);
  const persistedChannel = normalizeMessageChannel(params.persistedLastChannel);
  const sessionKeyChannelHint = resolveSessionKeyChannelHint(params.sessionKey);

  // When the turn originates from an internal/non-deliverable source, do not
  // replace an established external destination with internal routing ids
  // (e.g., session/webchat ids).
  if (!isExternalRoutingChannel(originatingChannel)) {
    const hasExternalFallback =
      isExternalRoutingChannel(persistedChannel) || isExternalRoutingChannel(sessionKeyChannelHint);
    if (hasExternalFallback && params.persistedLastTo) {
      return params.persistedLastTo;
    }
  }

  return params.originatingToRaw || params.toRaw || params.persistedLastTo;
}

export function maybeRetireLegacyMainDeliveryRoute(params: {
  sessionCfg: { dmScope?: string } | undefined;
  sessionKey: string;
  sessionStore: Record<string, SessionEntry>;
  agentId: string;
  mainKey: string;
  isGroup: boolean;
  ctx: MsgContext;
}): LegacyMainDeliveryRetirement | undefined {
  const dmScope = params.sessionCfg?.dmScope ?? "main";
  if (dmScope === "main" || params.isGroup) {
    return undefined;
  }
  const canonicalMainSessionKey = buildAgentMainSessionKey({
    agentId: params.agentId,
    mainKey: params.mainKey,
  }).toLowerCase();
  if (params.sessionKey === canonicalMainSessionKey) {
    return undefined;
  }
  const legacyMain = params.sessionStore[canonicalMainSessionKey];
  if (!legacyMain) {
    return undefined;
  }
  const legacyRouteKey = deliveryContextKey(deliveryContextFromSession(legacyMain));
  if (!legacyRouteKey) {
    return undefined;
  }
  const activeDirectRouteKey = deliveryContextKey(
    normalizeDeliveryContext({
      channel: params.ctx.OriginatingChannel as string | undefined,
      to: params.ctx.OriginatingTo || params.ctx.To,
      accountId: params.ctx.AccountId,
      threadId: params.ctx.MessageThreadId,
    }),
  );
  if (!activeDirectRouteKey || activeDirectRouteKey !== legacyRouteKey) {
    return undefined;
  }
  if (
    legacyMain.deliveryContext === undefined &&
    legacyMain.lastChannel === undefined &&
    legacyMain.lastTo === undefined &&
    legacyMain.lastAccountId === undefined &&
    legacyMain.lastThreadId === undefined
  ) {
    return undefined;
  }
  return {
    key: canonicalMainSessionKey,
    entry: {
      ...legacyMain,
      deliveryContext: undefined,
      lastChannel: undefined,
      lastTo: undefined,
      lastAccountId: undefined,
      lastThreadId: undefined,
    },
  };
}
