// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
// Licensed under the Apache License, Version 2.0

import fs from "node:fs/promises";
import path from "node:path";

import type { IAiLogger, IToolArguments, IToolDefinition } from "@gadget/ai";
import { DroneTool } from "../tool.ts";
import { resolveProjectPath, toolError } from "./common.ts";

export class FileWriteTool extends DroneTool {
  get name(): string {
    return "file_write";
  }

  get category(): string {
    return "system";
  }

  public definition: IToolDefinition = {
    type: "function",
    function: {
      name: this.name,
      description: "Create a new project file or overwrite an existing file with the provided UTF-8 content. Parent directories are created automatically.",
      parameters: {
        type: "object",
        properties: {
          path: { type: "string", description: "Path to create or overwrite, relative to the project root." },
          content: { type: "string", description: "The content to write to the file. Empty string is allowed." },
        },
        required: ["path", "content"],
      },
    },
  };

  public async execute(args: IToolArguments, logger: IAiLogger): Promise<string> {
    const filePath = args.path;
    const content = args.content;

    if (typeof filePath !== "string" || filePath.trim().length === 0) {
      return toolError({
        code: "MISSING_PARAMETER",
        message: "File path must not be empty.",
        parameter: "path",
        recoveryHint: "Provide a valid file path within the project directory.",
      });
    }
    if (content === undefined || typeof content !== "string") {
      return toolError({
        code: "MISSING_PARAMETER",
        message: "Content must be a string and must not be undefined.",
        parameter: "content",
        recoveryHint: "Provide the content to write to the file. Use an empty string to create an empty file.",
      });
    }

    const resolved = resolveProjectPath(this.toolbox, filePath);
    if (typeof resolved === "string") return resolved;

    try {
      await fs.mkdir(path.dirname(resolved.absolutePath), { recursive: true });

      let created = true;
      try {
        const stat = await fs.stat(resolved.absolutePath);
        created = !stat.isFile();
      } catch {
        created = true;
      }

      await fs.writeFile(resolved.absolutePath, content, "utf-8");
      const byteCount = Buffer.byteLength(content, "utf-8");

      return [
        `PATH: ${resolved.displayPath}`,
        "FILE OPERATION: write",
        `CREATED: ${created ? "true" : "false"}`,
        `BYTES WRITTEN: ${byteCount}`,
        "---",
        `File written: ${resolved.displayPath} (${byteCount} bytes)`,
      ].join("\n");
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      logger.error("failed to write file", { path: resolved.displayPath, error: errorMessage });
      return toolError({
        code: "OPERATION_FAILED",
        message: `Failed to write file: ${errorMessage}`,
      });
    }
  }
}
