import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * Git Diff Tool
 *
 * View changes between states (staged, unstaged, or against a commit/branch).
 */
import { Box, Text } from 'ink';
import { useTerminalWidth } from '../../hooks/useTerminalWidth.js';
import { useTheme } from '../../hooks/useTheme.js';
import { jsonSchema, tool } from '../../types/core.js';
import { formatError } from '../../utils/error-formatter.js';
import { execGit, truncateDiff } from './utils.js';
// ============================================================================
// Execution
// ============================================================================
const executeGitDiff = async (args) => {
    try {
        const gitArgs = ['diff'];
        // Add --cached for staged changes
        if (args.staged) {
            gitArgs.push('--cached');
        }
        // Add base reference (branch or commit)
        if (args.base) {
            gitArgs.push(args.base);
        }
        // Show stat only
        if (args.stat) {
            gitArgs.push('--stat');
        }
        // Specific file
        if (args.file) {
            gitArgs.push('--', args.file);
        }
        const output = await execGit(gitArgs);
        if (!output.trim()) {
            if (args.staged) {
                return 'No staged changes.';
            }
            if (args.base) {
                return `No differences with ${args.base}.`;
            }
            return 'No unstaged changes.';
        }
        // Truncate if too long (unless stat mode which is already compact)
        if (!args.stat) {
            const { content, truncated, totalLines } = truncateDiff(output, 500);
            if (truncated) {
                return `${content}\n\n[Total: ${totalLines} lines]`;
            }
        }
        return output;
    }
    catch (error) {
        return `Error: ${formatError(error)}`;
    }
};
// ============================================================================
// Tool Definition
// ============================================================================
const gitDiffCoreTool = tool({
    description: 'View git diff of changes. Shows unstaged changes by default, use staged=true for staged changes, or base to compare against a branch/commit.',
    inputSchema: jsonSchema({
        type: 'object',
        properties: {
            staged: {
                type: 'boolean',
                description: 'Show staged changes instead of unstaged (default: false)',
            },
            file: {
                type: 'string',
                description: 'Show diff for a specific file only',
            },
            base: {
                type: 'string',
                description: 'Compare against a branch or commit (e.g., "main", "HEAD~3")',
            },
            stat: {
                type: 'boolean',
                description: 'Show only diffstat summary instead of full diff',
            },
        },
        required: [],
    }),
    execute: async (args, _options) => {
        return await executeGitDiff(args);
    },
});
// ============================================================================
// Formatter
// ============================================================================
function GitDiffFormatter({ args, result, }) {
    const boxWidth = useTerminalWidth();
    const { colors } = useTheme();
    // Parse result for stats
    let filesChanged = 0;
    let insertions = 0;
    let deletions = 0;
    let isEmpty = false;
    if (result) {
        isEmpty =
            result.includes('No staged changes') ||
                result.includes('No unstaged changes') ||
                result.includes('No differences');
        // Parse diffstat summary line
        const statMatch = result.match(/(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/);
        if (statMatch) {
            filesChanged = parseInt(statMatch[1], 10) || 0;
            insertions = parseInt(statMatch[2], 10) || 0;
            deletions = parseInt(statMatch[3], 10) || 0;
        }
    }
    // Determine what we're comparing
    let comparing = 'working tree vs HEAD';
    if (args.staged) {
        comparing = 'staged vs HEAD';
    }
    if (args.base) {
        comparing = `working tree vs ${args.base}`;
        if (args.staged) {
            comparing = `staged vs ${args.base}`;
        }
    }
    return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, width: boxWidth, children: [_jsx(Text, { color: colors.tool, children: "\u2692 git_diff" }), _jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Comparing: " }), _jsx(Text, { color: colors.text, children: comparing })] }), args.file && (_jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "File: " }), _jsx(Text, { wrap: "truncate-end", color: colors.primary, children: args.file })] })), args.stat && (_jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Mode: " }), _jsx(Text, { color: colors.text, children: "stat only" })] })), isEmpty && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.success, children: "\u2713 No changes" }) })), !isEmpty && filesChanged > 0 && (_jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Stats: " }), _jsxs(Text, { color: colors.text, children: [filesChanged, " files, "] }), _jsxs(Text, { color: colors.success, children: ["+", insertions] }), _jsx(Text, { color: colors.text, children: ", " }), _jsxs(Text, { color: colors.error, children: ["-", deletions] })] }))] }));
}
const formatter = (args, result) => {
    return _jsx(GitDiffFormatter, { args: args, result: result });
};
// ============================================================================
// Export
// ============================================================================
export const gitDiffTool = {
    name: 'git_diff',
    tool: gitDiffCoreTool,
    formatter,
    readOnly: true,
};
//# sourceMappingURL=git-diff.js.map