import type { AgentHeartbeatDraft } from "@/lib/openclaw/agent-heartbeat";
import {
  applyPresetHeartbeat,
  defaultHeartbeatForPreset,
  resolveHeartbeatDraft
} from "@/lib/openclaw/agent-heartbeat";
import {
  AGENT_BOOTSTRAP_FILE_OPTIONS,
  buildAgentBootstrapFileDrafts,
  rebaseAgentBootstrapFileDrafts,
  type AgentBootstrapFileDraft
} from "@/lib/openclaw/agent-bootstrap-files";
import { getAgentPresetMeta, resolveAgentPolicy } from "@/lib/openclaw/agent-presets";
import type { AgentPolicy, AgentPreset, MissionControlSnapshot } from "@/lib/agentos/contracts";

export type AgentDraft = {
  workspaceId: string;
  modelId: string;
  name: string;
  emoji: string;
  theme: string;
  avatar: string;
  policy: AgentPolicy;
  heartbeat: AgentHeartbeatDraft;
  channelIds: string[];
};

export type {
  AgentBootstrapFileDraft,
  AgentBootstrapFileKind,
  AgentBootstrapFilePath
} from "@/lib/openclaw/agent-bootstrap-files";

export { AGENT_BOOTSTRAP_FILE_OPTIONS };

export function buildAgentDraft(workspaceId: string, seed: Partial<AgentDraft> = {}): AgentDraft {
  const policy = resolveAgentPolicy(seed.policy?.preset ?? "worker", seed.policy);
  const presetMeta = getAgentPresetMeta(policy.preset);
  const heartbeat = resolveHeartbeatDraft(policy.preset, seed.heartbeat);

  return {
    workspaceId,
    modelId: seed.modelId ?? "",
    name: seed.name ?? presetMeta.defaultName,
    emoji: seed.emoji ?? presetMeta.defaultEmoji,
    theme: seed.theme ?? presetMeta.defaultTheme,
    avatar: seed.avatar ?? "",
    policy,
    heartbeat,
    channelIds: Array.from(
      new Set(
        (seed.channelIds ?? []).filter((entry): entry is string => typeof entry === "string" && Boolean(entry.trim()))
      )
    )
  };
}

export function resolveSuggestedAgentModelId(
  snapshot: Pick<MissionControlSnapshot, "agents" | "diagnostics" | "models">,
  workspaceId?: string | null
) {
  const defaultModel = snapshot.diagnostics.modelReadiness.defaultModelReady
    ? normalizeModelId(
        snapshot.diagnostics.modelReadiness.resolvedDefaultModel ||
        snapshot.diagnostics.modelReadiness.defaultModel
      )
    : null;

  if (defaultModel && isSnapshotModelUsable(snapshot, defaultModel)) {
    return defaultModel;
  }

  const workspaceModel = snapshot.agents
    .filter((agent) => !workspaceId || agent.workspaceId === workspaceId)
    .map((agent) => normalizeModelId(agent.modelId))
    .find((modelId) => modelId && isSnapshotModelUsable(snapshot, modelId));

  if (workspaceModel) {
    return workspaceModel;
  }

  const recommendedModel = normalizeModelId(snapshot.diagnostics.modelReadiness.recommendedModelId);

  if (recommendedModel && isSnapshotModelUsable(snapshot, recommendedModel)) {
    return recommendedModel;
  }

  return snapshot.models
    .map((model) => normalizeModelId(model.id))
    .find((modelId) => modelId && isSnapshotModelUsable(snapshot, modelId)) ?? "";
}

function normalizeModelId(value: string | null | undefined) {
  const normalized = value?.trim();
  return normalized && normalized !== "unassigned" ? normalized : null;
}

export function isSnapshotModelUsable(
  snapshot: Pick<MissionControlSnapshot, "models">,
  modelId: string
) {
  const model = snapshot.models.find((entry) => entry.id === modelId);

  if (!model) {
    return false;
  }

  return model.missing !== true && model.available !== false;
}

export function buildUniqueAgentId(
  agents: MissionControlSnapshot["agents"],
  workspaceSlug: string | undefined,
  agentName: string
) {
  const baseId = buildScopedAgentId(workspaceSlug, agentName);

  if (!baseId) {
    return "";
  }

  const existingAgentIds = new Set(agents.map((agent) => agent.id));

  if (!existingAgentIds.has(baseId)) {
    return baseId;
  }

  let suffix = 2;
  let candidate = `${baseId}-${suffix}`;

  while (existingAgentIds.has(candidate)) {
    suffix += 1;
    candidate = `${baseId}-${suffix}`;
  }

  return candidate;
}

export function buildScopedAgentId(workspaceSlug: string | undefined, agentName: string) {
  const normalizedWorkspaceSlug = slugify(workspaceSlug ?? "");
  const normalizedAgentName = slugify(agentName) || "agent";

  return normalizedWorkspaceSlug ? `${normalizedWorkspaceSlug}-${normalizedAgentName}` : normalizedAgentName;
}

export function slugify(value: string) {
  return value
    .toLowerCase()
    .normalize("NFKD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
}

export function applyAgentPreset(draft: AgentDraft, preset: AgentPreset): AgentDraft {
  const previousMeta = getAgentPresetMeta(draft.policy.preset);
  const nextMeta = getAgentPresetMeta(preset);
  const nextPolicy = resolveAgentPolicy(preset);

  return {
    ...draft,
    name: !draft.name || draft.name === previousMeta.defaultName ? nextMeta.defaultName : draft.name,
    emoji: !draft.emoji || draft.emoji === previousMeta.defaultEmoji ? nextMeta.defaultEmoji : draft.emoji,
    theme: !draft.theme || draft.theme === previousMeta.defaultTheme ? nextMeta.defaultTheme : draft.theme,
    policy: nextPolicy,
    heartbeat: applyPresetHeartbeat(draft.heartbeat, draft.policy.preset, preset)
  };
}

export { defaultHeartbeatForPreset };

export function buildAgentBootstrapFileDraftsForDraft(
  draft: Pick<AgentDraft, "name" | "emoji" | "theme" | "avatar" | "policy" | "heartbeat">
) {
  return buildAgentBootstrapFileDrafts({
    name: draft.name,
    emoji: draft.emoji,
    theme: draft.theme,
    avatar: draft.avatar,
    preset: draft.policy.preset,
    heartbeat: draft.heartbeat
  });
}

export function rebaseAgentBootstrapFilesForDraft(
  currentFiles: AgentBootstrapFileDraft[],
  draft: Pick<AgentDraft, "name" | "emoji" | "theme" | "avatar" | "policy" | "heartbeat">
) {
  return rebaseAgentBootstrapFileDrafts(currentFiles, buildAgentBootstrapFileDraftsForDraft(draft));
}
