// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: GPL-3.0-or-later

import { readFile } from "node:fs/promises";
import { basename } from "node:path";
import { expandHomePath } from "../../util/path.js";
import { applyConfigOverrides, loadConfig } from "../../config/loader.js";
import { createWorkspace } from "../../workspace/manager.js";
import { writeWorkspaceFile } from "../../workspace/content.js";
import { createGrepTool } from "../../agent/tools/grep.js";
import { createReadTool } from "../../agent/tools/read.js";
import { createLsTool } from "../../agent/tools/ls.js";
import { createFindTool } from "../../agent/tools/find.js";
import { createWebFetchTool } from "../../agent/tools/web-fetch.js";
import { createWebSearchTool } from "../../agent/tools/web-search.js";
import { runAgent } from "../../agent/runner.js";
import { buildWebPrompt } from "../../agent/prompts/web.js";
import { createEventLogger, printUsageSummary } from "../output.js";
import { ConfigError, FetchError } from "../../util/errors.js";

const INJECT_THRESHOLD = 50 * 1024;

export interface WebCommandOptions {
  query: string;
  url?: string;
  model?: string;
  verbose: boolean;
  cleanup: boolean;
}

export async function runWebCommand(options: WebCommandOptions): Promise<void> {
  const { config } = await loadConfig();
  const overrides = applyConfigOverrides(config, {
    defaults: { model: options.model ?? config.defaults.model, cleanup: options.cleanup },
    web: { model: options.model ?? config.web.model },
  });

  const workspace = await createWorkspace({ cleanup: overrides.defaults.cleanup });

  try {
    const logger = createEventLogger({ verbose: options.verbose });

    const kagiSession =
      overrides.web.kagi_session_token ?? overrides.defaults.kagi_session_token ?? process.env["KAGI_SESSION_TOKEN"];
    const tabstackKey =
      overrides.web.tabstack_api_key ??
      overrides.defaults.tabstack_api_key ??
      process.env["TABSTACK_API_KEY"];

    if (!kagiSession) {
      throw new ConfigError("Web search requires KAGI_SESSION_TOKEN (set via environment or config)");
    }
    if (!tabstackKey) {
      throw new ConfigError("Web fetch requires TABSTACK_API_KEY (set via environment or config)");
    }

    let systemPrompt = buildWebPrompt({
      currentTime: new Date().toISOString(),
    });
    const promptPath = overrides.web.system_prompt_path;
    if (promptPath) {
      systemPrompt = await readFile(expandHomePath(promptPath), "utf8");
    }

    const tools = [
      createWebSearchTool(kagiSession),
      createWebFetchTool(tabstackKey),
      createReadTool(workspace.path),
      createGrepTool(workspace.path),
      createLsTool(workspace.path),
      createFindTool(workspace.path),
    ];

    let seededContext = "";
    if (options.url) {
      const fetchTool = createWebFetchTool(tabstackKey);
      try {
        const result = await fetchTool.execute("prefetch", { url: options.url, nocache: false });
        const text = result.content
          .map((block) => (block.type === "text" ? block.text ?? "" : ""))
          .join("");
        if (text.length <= INJECT_THRESHOLD) {
          seededContext = text;
        } else {
          const filename = `web/${basename(new URL(options.url).pathname) || "index"}.md`;
          await writeWorkspaceFile(workspace.path, filename, text);
          seededContext = `Content from ${options.url} was too large to include directly. It has been saved to ${filename} in your workspace.`;
        }
      } catch (error: any) {
        throw new FetchError(options.url, error?.message ?? String(error));
      }
    }

    const query = seededContext
      ? `${options.query}\n\n<attached_content url="${options.url}">\n${seededContext}\n</attached_content>`
      : options.query;

    const result = await runAgent(query, {
      model: overrides.web.model ?? overrides.defaults.model,
      systemPrompt,
      tools,
      onEvent: logger,
      config: overrides,
    });

    process.stdout.write(result.message + "\n");
    printUsageSummary(result.usage as any, result.requestCount);
  } finally {
    await workspace.cleanup();
  }
}
