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

import { Type } from "@sinclair/typebox";
import type { AgentTool } from "@mariozechner/pi-agent-core";
import simpleGit from "simple-git";
import { ToolInputError } from "../../../util/errors.js";

// Trust boundary: refs and paths are passed directly to simple-git, which is
// scoped to the workspace. The user chose to clone this repo, so its contents
// are trusted. See AGENTS.md § Workspace Sandboxing.

const DEFAULT_LOG_LIMIT = 20;

const LogSchema = Type.Object({
  path: Type.Optional(Type.String({ description: "Filter to commits touching this path" })),
  author: Type.Optional(Type.String({ description: "Filter by author name/email" })),
  since: Type.Optional(Type.String({ description: "Commits after this date (e.g., 2024-01-01)" })),
  until: Type.Optional(Type.String({ description: "Commits before this date" })),
  n: Type.Optional(Type.Number({ description: "Maximum number of commits (default: 20)" })),
  oneline: Type.Optional(Type.Boolean({ description: "Compact one-line format (default: false)" })),
});

export const createGitLogTool = (workspacePath: string): AgentTool => ({
  name: "git_log",
  label: "Git Log",
  description: "View commit history with optional path, author, and date filters.",
  parameters: LogSchema as any,
  execute: async (_toolCallId: string, params: any) => {
    const git = simpleGit(workspacePath);
    const options: string[] = [];

    const limit = params.n !== undefined ? params.n : DEFAULT_LOG_LIMIT;
    if (typeof limit !== "number" || Number.isNaN(limit) || limit <= 0) {
      throw new ToolInputError("n must be a positive number");
    }
    options.push("-n", String(Math.floor(limit)));
    if (params.oneline) options.push("--oneline");
    if (params.author !== undefined) {
      if (!String(params.author).trim()) {
        throw new ToolInputError("author must be a non-empty string");
      }
      options.push(`--author=${params.author}`);
    }
    if (params.since !== undefined) {
      if (!String(params.since).trim()) {
        throw new ToolInputError("since must be a non-empty string");
      }
      options.push(`--since=${params.since}`);
    }
    if (params.until !== undefined) {
      if (!String(params.until).trim()) {
        throw new ToolInputError("until must be a non-empty string");
      }
      options.push(`--until=${params.until}`);
    }

    const result = await git.log(options.concat(params.path ? ["--", params.path] : []));

    const text = result.all
      .map((entry) =>
        params.oneline
          ? `${entry.hash} ${entry.message}`
          : `${entry.hash} ${entry.date} ${entry.author_name} ${entry.message}`,
      )
      .join("\n");

    return {
      content: [{ type: "text", text }],
      details: { count: result.all.length },
    };
  },
});
