// 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 { toolError } from "../system/common.ts";
import { getGadgetDir, resolvePlanPath } from "./common.ts";

export class PlanFileWriteTool extends DroneTool {
  get name(): string {
    return "plan_file_write";
  }

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

  public definition: IToolDefinition = {
    type: "function",
    function: {
      name: this.name,
      description:
        "Create or overwrite a file in Gadget's .gadget directory. The .gadget directory is created automatically if it doesn't exist. This Plan-mode tool works in Gadget's own directory (.gadget) for storing plans, todos, and other knowledge. It does not affect project files.",
      parameters: {
        type: "object",
        properties: {
          path: { type: "string", description: "Path to create or overwrite, relative to the .gadget directory." },
          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 .gadget 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.",
      });
    }

    // Ensure .gadget directory exists before resolving — write tools create the dir
    const gadgetDir = getGadgetDir(this.toolbox);
    if (gadgetDir) {
      await fs.mkdir(gadgetDir, { recursive: true });
    }

    const resolved = resolvePlanPath(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 plan file", { path: resolved.displayPath, error: errorMessage });
      return toolError({
        code: "OPERATION_FAILED",
        message: `Failed to write file: ${errorMessage}`,
      });
    }
  }
}
