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

import type { IAiLogger, IToolArguments, IToolDefinition } from "@gadget/ai";
import { DroneTool } from "../tool.ts";
import { asPositiveInteger, getCacheDir, toolError } from "../system/common.ts";
import { WebFetcher } from "./web-fetcher.ts";

export class FetchUrlTool extends DroneTool {
  get name(): string {
    return "fetch_url";
  }

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

  public definition: IToolDefinition = {
    type: "function",
    function: {
      name: this.name,
      description: "Fetch a URL, convert readable page content to line-numbered Markdown, cache it in the drone .gadget/cache directory, and return an optional line range like file_read.",
      parameters: {
        type: "object",
        properties: {
          url: { type: "string", description: "The URL to fetch. Must start with http:// or https://." },
          startLine: { type: "number", description: "Starting line number (1-indexed). Defaults to 1." },
          endLine: { type: "number", description: "Ending line number (inclusive). Defaults to end of content." },
          useCache: { type: "boolean", description: "Use cached Markdown if available. Defaults to true." },
        },
        required: ["url"],
      },
    },
  };

  public async execute(args: IToolArguments, logger: IAiLogger): Promise<string> {
    const url = args.url;
    const startLine = asPositiveInteger(args.startLine) ?? 1;
    const endLine = args.endLine === undefined ? undefined : asPositiveInteger(args.endLine);
    const useCache = typeof args.useCache === "boolean" ? args.useCache : true;

    if (typeof url !== "string" || url.trim().length === 0) {
      return toolError({
        code: "MISSING_PARAMETER",
        message: "URL must not be empty.",
        parameter: "url",
        recoveryHint: "Provide a valid URL starting with http:// or https://.",
      });
    }
    if (!/^https?:\/\/.+/i.test(url)) {
      return toolError({
        code: "INVALID_PARAMETER",
        message: "URL must start with http:// or https://.",
        parameter: "url",
        expected: "A valid URL starting with http:// or https://.",
        example: "https://example.com",
      });
    }
    if (startLine < 1) {
      return toolError({
        code: "INVALID_PARAMETER",
        message: "startLine must be >= 1.",
        parameter: "startLine",
        expected: "A positive integer >= 1",
      });
    }
    if (endLine !== undefined && endLine < startLine) {
      return toolError({
        code: "INVALID_PARAMETER",
        message: "endLine must be >= startLine.",
        parameter: "endLine",
        expected: "An integer >= startLine",
      });
    }

    const cacheDir = getCacheDir(this.toolbox);
    if (!cacheDir) {
      return toolError({
        code: "OPERATION_NOT_ALLOWED",
        message: "No drone cache directory is configured for fetch_url.",
        recoveryHint: "Run this tool during an active Agent work order after workspace initialization.",
      });
    }

    try {
      logger.info("fetching URL", { url, startLine, endLine, useCache });
      const result = await new WebFetcher(cacheDir).fetchUrlWithRange(
        url,
        startLine,
        endLine,
        useCache,
      );

      return [
        `URL: ${result.url}`,
        `TITLE: ${result.title}`,
        `TOTAL LINES: ${result.totalLineCount}`,
        `LINES SHOWN: ${result.shownLineCount}`,
        "FETCH OPERATION: fetch_url",
        `CACHE: ${result.cacheStatus}`,
        "---",
        result.markdown,
      ].join("\n");
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      logger.error("failed to fetch URL", { url, error: errorMessage });

      if (errorMessage.toLowerCase().includes("timeout")) {
        return toolError({
          code: "TIMEOUT",
          message: `Request timed out while fetching: ${url}`,
          recoveryHint: "The page may be slow to load or unreachable.",
        });
      }
      if (errorMessage.includes("ENOTFOUND") || errorMessage.includes("ERR_NAME_NOT_RESOLVED")) {
        return toolError({
          code: "OPERATION_FAILED",
          message: `Failed to resolve hostname: ${url}`,
          recoveryHint: "Check the URL and ensure the domain is accessible.",
        });
      }
      if (errorMessage.includes("ERR_ABORTED") || errorMessage.includes("404")) {
        return toolError({
          code: "NOT_FOUND",
          message: `Page not found: ${url}`,
          recoveryHint: "The URL may be incorrect or the page may have been removed.",
        });
      }

      return toolError({
        code: "OPERATION_FAILED",
        message: `Failed to fetch URL: ${errorMessage}`,
      });
    }
  }
}
