import type { SubagentToolManifestItem, SubagentWorkerPolicy } from '../subagent/process_protocol.js';
import { requiresWorkspaceRootForTool } from './manifest.js';

export type ToolWorkerRuntimeStatus =
  | 'worker-local'
  | 'main-process-proxied'
  | 'disabled-in-worker'
  | 'not-selected';

export type ToolRuntimeRoute = 'worker-local' | 'main-process-proxy' | 'disabled';

export interface ToolWorkerRuntimeProjection {
  status: ToolWorkerRuntimeStatus;
  blockedReason: string | null;
  policyDerived: boolean;
  policySources: string[];
}

export interface BuildWorkerPolicyParams {
  sessionCwd?: string | null;
  workspaceRoots?: string[];
  allowShell?: boolean;
  readonly?: boolean;
  toolManifest: SubagentToolManifestItem[];
}

export interface ResolveToolWorkerRuntimeParams {
  toolName: string;
  manifest?: SubagentToolManifestItem;
  enabledToolNames: string[];
  disabledReasons?: Map<string, string>;
  policy: SubagentWorkerPolicy;
}

export function buildSubprocessWorkerPolicy(params: BuildWorkerPolicyParams): SubagentWorkerPolicy {
  const uniqueRoots = normalizeWorkspaceRoots([
    params.sessionCwd ?? undefined,
    ...(Array.isArray(params.workspaceRoots) ? params.workspaceRoots : []),
  ]);
  const workerLocalManifest = params.toolManifest.filter(
    item => (item.workerRoutingHint ?? (item.supportedInWorker ? 'local' : 'disabled')) === 'local'
  );
  const workerShellRequired = workerLocalManifest.some(item => item.requiresShell);
  const workerWriteRequired = workerLocalManifest.some(item => item.requiresWrite);

  return {
    workspaceRoots: uniqueRoots,
    allowShell: params.allowShell === undefined
      ? workerShellRequired
      : params.allowShell && workerShellRequired,
    readonly: params.readonly ?? !workerWriteRequired,
  };
}

export function resolveToolWorkerRuntime(
  params: ResolveToolWorkerRuntimeParams
): ToolWorkerRuntimeProjection {
  const disabledReasons = params.disabledReasons ?? new Map<string, string>();
  if (!params.enabledToolNames.includes(params.toolName)) {
    return {
      status: 'not-selected',
      blockedReason: disabledReasons.get(params.toolName) ?? 'not_selected_for_subagent',
      policyDerived: true,
      policySources: ['toolManifest', 'subagent-policy'],
    };
  }

  const manifest = params.manifest;
  const workerRoutingHint = manifest?.workerRoutingHint ?? (manifest?.supportedInWorker ? 'local' : 'disabled');

  if (!manifest || workerRoutingHint !== 'local') {
    if (workerRoutingHint === 'main-process-proxy' && manifest) {
      return resolveMainProcessProxyRuntime(manifest, params.policy);
    }

    return {
      status: 'disabled-in-worker',
      blockedReason: 'unsupported_in_worker',
      policyDerived: true,
      policySources: ['toolManifest', 'worker-support'],
    };
  }

  return resolveWorkerLocalRuntime(manifest, params.policy);
}

export function mapWorkerStatusToRuntimeRoute(status: ToolWorkerRuntimeStatus): ToolRuntimeRoute {
  if (status === 'worker-local') return 'worker-local';
  if (status === 'main-process-proxied') return 'main-process-proxy';
  return 'disabled';
}

export function normalizeWorkspaceRoots(values: Array<string | null | undefined>): string[] {
  return [...new Set(
    values
      .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)
      .map(value => value.trim())
  )];
}

function resolveMainProcessProxyRuntime(
  manifest: SubagentToolManifestItem,
  policy: SubagentWorkerPolicy
): ToolWorkerRuntimeProjection {
  if (requiresWorkspaceRootForTool(manifest.name) && (!policy.workspaceRoots || policy.workspaceRoots.length === 0)) {
    return {
      status: 'disabled-in-worker',
      blockedReason: 'workspace_root_required',
      policyDerived: true,
      policySources: ['session-workspace', 'main-process-proxy'],
    };
  }

  if (manifest.requiresShell && policy.allowShell !== true) {
    return {
      status: 'disabled-in-worker',
      blockedReason: 'shell_disabled_by_policy',
      policyDerived: true,
      policySources: ['toolManifest', 'main-process-proxy', 'worker-policy'],
    };
  }

  if (manifest.requiresWrite && policy.readonly !== false) {
    return {
      status: 'disabled-in-worker',
      blockedReason: 'write_blocked_by_readonly_policy',
      policyDerived: true,
      policySources: ['toolManifest', 'main-process-proxy', 'worker-policy'],
    };
  }

  return {
    status: 'main-process-proxied',
    blockedReason: 'requires_main_process_proxy',
    policyDerived: true,
    policySources: ['toolManifest', 'main-process-proxy'],
  };
}

function resolveWorkerLocalRuntime(
  manifest: SubagentToolManifestItem,
  policy: SubagentWorkerPolicy
): ToolWorkerRuntimeProjection {
  if (requiresWorkspaceRootForTool(manifest.name) && (!policy.workspaceRoots || policy.workspaceRoots.length === 0)) {
    return {
      status: 'disabled-in-worker',
      blockedReason: 'workspace_root_required',
      policyDerived: true,
      policySources: ['session-workspace', 'worker-policy'],
    };
  }

  if (manifest.requiresShell && policy.allowShell !== true) {
    return {
      status: 'disabled-in-worker',
      blockedReason: 'shell_disabled_by_policy',
      policyDerived: true,
      policySources: ['toolManifest', 'worker-policy'],
    };
  }

  if (manifest.requiresWrite && policy.readonly !== false) {
    return {
      status: 'disabled-in-worker',
      blockedReason: 'write_blocked_by_readonly_policy',
      policyDerived: true,
      policySources: ['toolManifest', 'worker-policy'],
    };
  }

  return {
    status: 'worker-local',
    blockedReason: null,
    policyDerived: true,
    policySources: ['toolManifest', 'worker-policy'],
  };
}
