'use strict';

const { resolveAgentRunContext } = require('./agent-run-context');
const { ToolRegistry } = require('../coding/tool-registry');
const { RuntimeToolExecutor } = require('./tool-executor');

const PROFILE_DEFAULTS = Object.freeze({
  chat: Object.freeze({
    profileId: 'chat',
    permissionProfile: 'assistant-safe',
    persistenceProfile: 'chat-ledger',
    outputContract: 'assistant-reply',
    toolsets: Object.freeze(['chat', 'memory', 'live', 'local', 'handoff']),
    capabilities: Object.freeze({
      memory: true,
      ctmContext: true,
      liveSources: true,
      mcp: true,
      skills: true,
      localTools: true,
      shell: true,
      fileRead: true,
      fileWrite: true,
      browser: true,
      codingHandoff: true,
      taskDelegation: false,
      sideEffects: 'permissioned',
    }),
  }),
  coding: Object.freeze({
    profileId: 'coding',
    permissionProfile: 'coding-workspace',
    persistenceProfile: 'jsonl-transcript',
    outputContract: 'coding-acceptance',
    toolsets: Object.freeze(['coding', 'memory', 'mcp', 'skills', 'local']),
    capabilities: Object.freeze({
      memory: true,
      ctmContext: true,
      liveSources: false,
      mcp: true,
      skills: true,
      localTools: true,
      shell: true,
      fileRead: true,
      fileWrite: true,
      browser: true,
      codingHandoff: false,
      taskDelegation: true,
      sideEffects: 'workspace',
    }),
  }),
  review: Object.freeze({
    profileId: 'review',
    permissionProfile: 'review-readonly',
    persistenceProfile: 'chat-ledger',
    outputContract: 'review-findings',
    toolsets: Object.freeze(['review', 'memory', 'project-read']),
    capabilities: Object.freeze({
      memory: true,
      ctmContext: true,
      liveSources: false,
      mcp: false,
      skills: false,
      localTools: false,
      shell: false,
      fileRead: true,
      fileWrite: false,
      browser: false,
      codingHandoff: false,
      taskDelegation: false,
      sideEffects: 'read-only',
    }),
  }),
});

function resolveWallERuntimeProfile(input = {}) {
  const context = input.context?.version === 1 && input.context?.agentMode
    ? input.context
    : resolveAgentRunContext(input);
  const profileId = normalizeRuntimeProfileId(
    input.runtimeProfile
      || input.runtime_profile
      || input.profileId
      || input.profile_id
      || context.agentMode
  );
  const defaults = PROFILE_DEFAULTS[profileId] || PROFILE_DEFAULTS.chat;
  const capabilities = {
    ...defaults.capabilities,
    ...(input.capabilities && typeof input.capabilities === 'object' ? input.capabilities : {}),
  };

  return {
    version: 1,
    profileId: defaults.profileId,
    context,
    channel: context.channel,
    source: context.source,
    agentMode: context.agentMode,
    agentKind: context.agentKind,
    taskType: context.taskType,
    sessionId: context.sessionId,
    ctmSessionId: context.ctmSessionId,
    agentSessionId: context.agentSessionId,
    chatSessionId: context.chatSessionId,
    cwd: context.cwd,
    jsonlPath: context.jsonlPath,
    capabilities,
    permissionProfile: input.permissionProfile || input.permission_profile || defaults.permissionProfile,
    persistenceProfile: input.persistenceProfile || input.persistence_profile || defaults.persistenceProfile,
    outputContract: input.outputContract || input.output_contract || defaults.outputContract,
    toolsets: Array.isArray(input.toolsets) && input.toolsets.length ? [...input.toolsets] : [...defaults.toolsets],
    warnings: [...(context.warnings || []), ...profileWarnings(context, defaults, capabilities)],
  };
}

function normalizeRuntimeProfileId(value) {
  const raw = String(value || '').trim().toLowerCase().replace(/_/g, '-');
  if (!raw) return 'chat';
  if (raw === 'assistant' || raw === 'walle-chat' || raw === 'wall-e-chat') return 'chat';
  if (raw === 'code' || raw === 'walle-coding' || raw === 'wall-e-coding') return 'coding';
  if (raw === 'code-review' || raw === 'reviewer') return 'review';
  return PROFILE_DEFAULTS[raw] ? raw : 'chat';
}

function profileWarnings(context, defaults, capabilities) {
  const warnings = [];
  if (defaults.profileId === 'review' && capabilities.fileWrite) {
    warnings.push({
      code: 'review-profile-write-capability',
      message: 'Review runtime profile must remain read-only',
    });
  }
  if (defaults.profileId === 'coding' && !context.agentSessionId) {
    warnings.push({
      code: 'coding-profile-missing-agent-session-id',
      message: 'Coding runtime profile should have a durable agent session id',
    });
  }
  return warnings;
}

function runtimeToolContext(runtimeProfile = {}, extra = {}) {
  return {
    ...extra,
    runtimeProfile: runtimeProfile.profileId || extra.runtimeProfile,
    permissionProfile: runtimeProfile.permissionProfile || extra.permissionProfile,
    persistenceProfile: runtimeProfile.persistenceProfile || extra.persistenceProfile,
    outputContract: runtimeProfile.outputContract || extra.outputContract,
    toolsets: extra.toolsets || runtimeProfile.toolsets || [],
    channel: runtimeProfile.channel || extra.channel,
    source: runtimeProfile.source || extra.source,
    agentMode: runtimeProfile.agentMode || extra.agentMode,
    agentKind: runtimeProfile.agentKind || extra.agentKind,
    taskType: runtimeProfile.taskType || extra.taskType,
    sessionId: runtimeProfile.sessionId || extra.sessionId,
    ctmSessionId: runtimeProfile.ctmSessionId || extra.ctmSessionId,
    agentSessionId: runtimeProfile.agentSessionId || extra.agentSessionId,
    chatSessionId: runtimeProfile.chatSessionId || extra.chatSessionId,
    cwd: runtimeProfile.cwd || extra.cwd,
  };
}

function createWallEToolRegistry({
  runtimeProfile = null,
  builtinTools = [],
  middleware = null,
  localTools = null,
  localToolNames = [],
  mcpClient = null,
  skillRunner = null,
  executeBuiltinTool = null,
  prepareBuiltinArgs = null,
  unknownToolHandler = null,
  specialHandlers = {},
  ...rest
} = {}) {
  const localSet = new Set((localToolNames || []).filter(Boolean));
  const tools = (builtinTools || []).map((tool) => {
    if (!tool || !tool.name || typeof tool.execute === 'function') return tool;
    if (!executeBuiltinTool || localSet.has(tool.name)) return tool;
    return {
      ...tool,
      prepareArgs: typeof prepareBuiltinArgs === 'function'
        ? (args, ctx) => prepareBuiltinArgs(tool.name, args, ctx)
        : tool.prepareArgs,
      execute: (args, ctx) => executeBuiltinTool(tool.name, args, ctx),
    };
  });

  return new ToolRegistry({
    ...rest,
    builtinTools: tools,
    middleware,
    localTools,
    mcpClient,
    skillRunner,
    specialHandlers,
    unknownToolHandler,
  });
}

async function getRuntimeToolDefinitions(registry, runtimeProfile, extra = {}) {
  if (!registry || typeof registry.getDefinitions !== 'function') return [];
  return registry.getDefinitions(runtimeToolContext(runtimeProfile, extra));
}

async function executeRuntimeTool(registry, runtimeProfile, name, args = {}, extra = {}) {
  if (!registry || typeof registry.execute !== 'function') {
    return { invalid: true, error: `Tool registry unavailable for ${name}` };
  }
  return registry.execute(name, args, runtimeToolContext(runtimeProfile, extra));
}

module.exports = {
  PROFILE_DEFAULTS,
  RuntimeToolExecutor,
  createWallEToolRegistry,
  executeRuntimeTool,
  getRuntimeToolDefinitions,
  normalizeRuntimeProfileId,
  resolveWallERuntimeProfile,
  runtimeToolContext,
};
