import { BestAgentError } from "@best-agent/foundation";
import { resolve } from "node:path";
import { z } from "zod";
import type { ToolDefinition, ToolInputAdapter } from "../contracts.js";
import { toolInputSchema, typedToolInputSchema } from "../schema.js";
import {
  type NamedContentInput,
  type WorkspaceDirectoryInput,
  formatNamedContentInput,
  normalizeNamedContentInput,
  normalizeOptionalPathInput,
  truncate,
} from "./shared.js";

const VERIFY_SWIFT_PACKAGE_TIMEOUT_MS = 15 * 60 * 1000;
const NAMED_CONTENT_INPUT_SCHEMA = toolInputSchema(
  z.strictObject({
    content: z.string().describe("Full text content to persist."),
    path: z.string().describe("Artifact or attachment name to persist."),
  }),
);

export function createAttachTextTool(): ToolDefinition<NamedContentInput> {
  return {
    description: "Persist a text attachment for the current turn.",
    effect: "write",
    executionClass: "external-side-effect",
    idempotent: false,
    inputSchema: NAMED_CONTENT_INPUT_SCHEMA,
    name: "attach-text",
    source: "built-in",
    capabilities() {
      return [];
    },
    async execute(input, context) {
      const asset = await context.store.putAttachment({
        threadId: context.threadId,
        turnId: context.turnId,
        name: input.path,
        contentType: "text/plain",
        data: input.content,
      });
      return `attachment ${asset.name} saved`;
    },
    formatInput(input) {
      return formatNamedContentInput(input);
    },
    legacyAdapter: {
      adapt(input) {
        return normalizeNamedContentInput("attach-text", input);
      },
    } satisfies ToolInputAdapter<NamedContentInput>,
  };
}

export function createWriteArtifactTool(): ToolDefinition<NamedContentInput> {
  return {
    description: "Persist a text artifact for the current turn.",
    effect: "write",
    executionClass: "external-side-effect",
    idempotent: false,
    inputSchema: NAMED_CONTENT_INPUT_SCHEMA,
    name: "write-artifact",
    source: "built-in",
    capabilities() {
      return [];
    },
    async execute(input, context) {
      const asset = await context.store.putArtifact({
        threadId: context.threadId,
        turnId: context.turnId,
        name: input.path,
        contentType: "text/plain",
        data: input.content,
      });
      return `artifact ${asset.name} saved`;
    },
    formatInput(input) {
      return formatNamedContentInput(input);
    },
    legacyAdapter: {
      adapt(input) {
        return normalizeNamedContentInput("write-artifact", input);
      },
    } satisfies ToolInputAdapter<NamedContentInput>,
  };
}

export function createVerifySwiftPackageTool(): ToolDefinition<WorkspaceDirectoryInput> {
  return {
    description:
      "Run xcrun swift build inside the active workspace or a relative Swift package directory to verify compilation.",
    effect: "verify",
    executionClass: "workspace-mutation",
    idempotent: false,
    inputSchema: typedToolInputSchema<WorkspaceDirectoryInput>(
      z.strictObject({
        path: z.string().default("."),
      }),
    ),
    name: "verify-swift-package",
    source: "built-in",
    capabilities(input, context) {
      const packageDir = resolve(context.cwd, input.path);
      return [
        {
          group: "shell",
          argv: ["xcrun", "swift", "build"],
          cwd: packageDir,
        },
        {
          group: "filesystem",
          action: "read",
          path: packageDir,
          roots: [context.cwd],
        },
        {
          group: "filesystem",
          action: "write",
          path: packageDir,
          roots: [context.cwd],
        },
      ];
    },
    async execute(input, context) {
      const packageDir = resolve(context.cwd, input.path);
      return context.sandbox.runMutableCommand(["xcrun", "swift", "build"], packageDir, {
        timeoutMs: VERIFY_SWIFT_PACKAGE_TIMEOUT_MS,
      });
    },
    formatInput(input) {
      return input.path === "." ? "current workspace" : input.path;
    },
    legacyAdapter: {
      adapt(input, context) {
        const normalized = normalizeOptionalPathInput("verify-swift-package", input);
        const packageDir = resolve(context.cwd, normalized.path);
        if (!context.sandbox.exists(packageDir)) {
          throw new BestAgentError(
            "TOOL_INPUT_NOT_FOUND",
            `Path ${packageDir} does not exist in the workspace.`,
          );
        }
        if (!context.sandbox.isDirectory(packageDir)) {
          throw new BestAgentError(
            "TOOL_INPUT_NOT_FOUND",
            `Path ${packageDir} is not a directory. verify-swift-package requires a package directory.`,
          );
        }
        if (!context.sandbox.exists(resolve(packageDir, "Package.swift"))) {
          throw new BestAgentError(
            "TOOL_INPUT_NOT_FOUND",
            `Path ${packageDir} does not contain a Package.swift manifest.`,
          );
        }
        return normalized;
      },
    } satisfies ToolInputAdapter<WorkspaceDirectoryInput>,
    summarize(input, output) {
      if (output.trim().length === 0) {
        return `Tool verify-swift-package built ${input.path === "." ? "the current workspace" : input.path} successfully.`;
      }
      return `Tool verify-swift-package built ${input.path === "." ? "the current workspace" : input.path} and returned "${truncate(output)}".`;
    },
  };
}
