import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * Git Create PR Tool
 *
 * Generates pull request templates with auto-generated descriptions,
 * test plans, and reviewer suggestions based on commit history.
 */
import { Box, Text } from 'ink';
import React from 'react';
import ToolMessage from '../../components/tool-message.js';
import { ThemeContext } from '../../hooks/useTheme.js';
import { jsonSchema, tool } from '../../types/core.js';
import { execGit, getCommitsBetween, getCurrentBranch, getDefaultBranch, getSuggestedReviewers, isGitRepository, } from './utils.js';
/**
 * Categorize commits by type
 */
function categorizeCommits(commits) {
    const categories = new Map();
    for (const commit of commits) {
        const subject = commit.subject;
        // Parse conventional commit format
        const match = subject.match(/^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+?\))?(!)?:\s*(.+)/);
        let category;
        let description;
        if (match) {
            category = match[1];
            description = match[4] || subject;
        }
        else {
            // Non-conventional commit
            category = 'other';
            description = subject;
        }
        if (!categories.has(category)) {
            categories.set(category, []);
        }
        categories.get(category)?.push(description);
    }
    return categories;
}
/**
 * Generate PR title from commits
 */
function generatePRTitle(commits, branch) {
    if (commits.length === 0) {
        // Use branch name as fallback
        const branchParts = branch.split('/');
        const branchName = branchParts[branchParts.length - 1];
        return (branchName
            ?.replace(/-/g, ' ')
            .replace(/_/g, ' ')
            .replace(/^\w/, c => c.toUpperCase()) || 'Update');
    }
    if (commits.length === 1) {
        return commits[0].subject;
    }
    // Multiple commits - summarize
    const categories = categorizeCommits(commits);
    // Priority order for title
    const titlePriority = ['feat', 'fix', 'refactor', 'perf', 'other'];
    for (const category of titlePriority) {
        const items = categories.get(category);
        if (items && items.length > 0) {
            if (items.length === 1) {
                return items[0];
            }
            // Summarize multiple items
            const prefix = category === 'feat' ? 'Add' : category === 'fix' ? 'Fix' : 'Update';
            return `${prefix} ${items.length} ${category === 'feat' ? 'features' : 'changes'}`;
        }
    }
    return commits[0].subject;
}
/**
 * Generate PR summary from categorized commits
 */
function generateSummary(categories) {
    const summary = [];
    const categoryLabels = {
        feat: 'New Features',
        fix: 'Bug Fixes',
        docs: 'Documentation',
        style: 'Style Changes',
        refactor: 'Code Refactoring',
        perf: 'Performance Improvements',
        test: 'Test Updates',
        build: 'Build Changes',
        ci: 'CI/CD Updates',
        chore: 'Maintenance',
        other: 'Other Changes',
    };
    for (const [category, items] of categories) {
        const label = categoryLabels[category] || 'Changes';
        summary.push(`**${label}:**`);
        for (const item of items) {
            summary.push(`- ${item}`);
        }
        summary.push('');
    }
    return summary;
}
/**
 * Generate test plan suggestions
 */
function generateTestPlan(categories, changedFiles) {
    const testPlan = [];
    // Check if there are new features
    if (categories.has('feat')) {
        testPlan.push('- [ ] Verify new functionality works as expected');
        testPlan.push('- [ ] Check for edge cases and error handling');
    }
    // Check if there are bug fixes
    if (categories.has('fix')) {
        testPlan.push('- [ ] Verify the bug is fixed');
        testPlan.push('- [ ] Ensure no regression in related functionality');
    }
    // Check for UI changes
    const hasUIChanges = changedFiles.some(f => f.includes('component') ||
        f.endsWith('.tsx') ||
        f.endsWith('.css') ||
        f.endsWith('.scss'));
    if (hasUIChanges) {
        testPlan.push('- [ ] Visual inspection of UI changes');
        testPlan.push('- [ ] Test responsive behavior');
    }
    // Check for API changes
    const hasAPIChanges = changedFiles.some(f => f.includes('api') || f.includes('route') || f.includes('endpoint'));
    if (hasAPIChanges) {
        testPlan.push('- [ ] Test API endpoints');
        testPlan.push('- [ ] Verify request/response format');
    }
    // Generic tests
    testPlan.push('- [ ] Run existing test suite');
    testPlan.push('- [ ] Build succeeds without errors');
    return testPlan;
}
/**
 * Detect breaking changes from commits
 */
function detectBreakingChanges(commits) {
    const breakingChanges = [];
    for (const commit of commits) {
        // Check for breaking change indicator
        if (commit.subject.includes('!:')) {
            const match = commit.subject.match(/!:\s*(.+)/);
            if (match) {
                breakingChanges.push(match[1]);
            }
        }
        // Check body for BREAKING CHANGE
        if (commit.body.includes('BREAKING CHANGE')) {
            const match = commit.body.match(/BREAKING CHANGE:\s*(.+)/);
            if (match) {
                breakingChanges.push(match[1]);
            }
        }
    }
    return breakingChanges;
}
/**
 * Generate suggested labels based on changes
 */
function suggestLabels(categories) {
    const labels = [];
    if (categories.has('feat'))
        labels.push('enhancement');
    if (categories.has('fix'))
        labels.push('bug');
    if (categories.has('docs'))
        labels.push('documentation');
    if (categories.has('perf'))
        labels.push('performance');
    if (categories.has('test'))
        labels.push('testing');
    return labels;
}
/**
 * Generate the full PR template
 */
async function generatePRTemplate(targetBranch, includeSummary) {
    const currentBranch = await getCurrentBranch();
    const commits = await getCommitsBetween(targetBranch);
    // Get changed files from diff
    let changedFiles = [];
    try {
        const diffFiles = await execGit([
            'diff',
            '--name-only',
            `${targetBranch}...HEAD`,
        ]);
        changedFiles = diffFiles.split('\n').filter(f => f.trim());
    }
    catch {
        // May fail if target branch doesn't exist locally
    }
    const categories = categorizeCommits(commits);
    const title = generatePRTitle(commits, currentBranch);
    const summary = includeSummary ? generateSummary(categories) : [];
    const testPlan = generateTestPlan(categories, changedFiles);
    const breakingChanges = detectBreakingChanges(commits);
    const suggestedReviewers = await getSuggestedReviewers(changedFiles.map(f => ({
        path: f,
        status: 'modified',
        additions: 0,
        deletions: 0,
        isBinary: false,
    })));
    const labels = suggestLabels(categories);
    return {
        title,
        summary: summary.join('\n'),
        changes: Array.from(categories.entries()).flatMap(([cat, items]) => items.map(item => `${cat}: ${item}`)),
        testPlan,
        breakingChanges: breakingChanges.length > 0 ? breakingChanges : undefined,
        suggestedReviewers: suggestedReviewers.length > 0 ? suggestedReviewers : undefined,
        labels: labels.length > 0 ? labels : undefined,
    };
}
/**
 * Execute the git_create_pr tool
 */
const executeGitCreatePR = async (args) => {
    // Check if we're in a git repository
    if (!(await isGitRepository())) {
        return 'Error: Not a git repository. Please run this command from within a git repository.';
    }
    const currentBranch = await getCurrentBranch();
    // Determine target branch
    let targetBranch = args.targetBranch;
    if (!targetBranch) {
        targetBranch = await getDefaultBranch();
    }
    // Check if on target branch
    if (currentBranch === targetBranch) {
        return `Error: Currently on ${targetBranch}. Please switch to a feature branch before creating a PR.`;
    }
    // Generate PR template
    const template = await generatePRTemplate(targetBranch, args.includeSummary !== false);
    // Build response
    const responseLines = [];
    responseLines.push('=== Pull Request Template ===');
    responseLines.push('');
    responseLines.push(`Branch: ${currentBranch} -> ${targetBranch}`);
    responseLines.push(`Draft: ${args.draft ? 'Yes' : 'No'}`);
    responseLines.push('');
    responseLines.push('--- Title ---');
    responseLines.push(template.title);
    responseLines.push('');
    responseLines.push('--- Description ---');
    responseLines.push('## Summary');
    if (template.summary) {
        responseLines.push(template.summary);
    }
    else {
        responseLines.push('<!-- Add a summary of changes -->');
    }
    responseLines.push('');
    responseLines.push('## Test Plan');
    for (const item of template.testPlan) {
        responseLines.push(item);
    }
    responseLines.push('');
    if (template.breakingChanges && template.breakingChanges.length > 0) {
        responseLines.push('## Breaking Changes');
        for (const change of template.breakingChanges) {
            responseLines.push(`- ${change}`);
        }
        responseLines.push('');
    }
    if (template.suggestedReviewers && template.suggestedReviewers.length > 0) {
        responseLines.push('--- Suggested Reviewers ---');
        for (const reviewer of template.suggestedReviewers) {
            responseLines.push(`  - ${reviewer}`);
        }
        responseLines.push('');
    }
    if (template.labels && template.labels.length > 0) {
        responseLines.push('--- Suggested Labels ---');
        responseLines.push(`  ${template.labels.join(', ')}`);
        responseLines.push('');
    }
    responseLines.push('--- Commands ---');
    responseLines.push('');
    responseLines.push('To create this PR using GitHub CLI:');
    const draftFlag = args.draft ? ' --draft' : '';
    responseLines.push(`gh pr create --title "${template.title}" --body "..." --base ${targetBranch}${draftFlag}`);
    responseLines.push('');
    responseLines.push('Or copy the template above and create the PR manually on GitHub.');
    return responseLines.join('\n');
};
// AI SDK tool definition with execute function
const gitCreatePRCoreTool = tool({
    description: 'Generate a pull request template with auto-generated description, test plan, and reviewer suggestions based on commit history.',
    inputSchema: jsonSchema({
        type: 'object',
        properties: {
            targetBranch: {
                type: 'string',
                description: 'The target branch for the PR (e.g., "main", "develop"). Defaults to the default branch.',
            },
            draft: {
                type: 'boolean',
                description: 'Whether to create the PR as a draft. Default: false',
            },
            includeSummary: {
                type: 'boolean',
                description: 'Whether to include a detailed summary of changes. Default: true',
            },
        },
        required: [],
    }),
    execute: async (args, _options) => {
        return await executeGitCreatePR(args);
    },
});
// Formatter component
const GitCreatePRFormatter = React.memo(({ args, result }) => {
    const themeContext = React.useContext(ThemeContext);
    if (!themeContext) {
        throw new Error('ThemeContext is required');
    }
    const { colors } = themeContext;
    const [preview, setPreview] = React.useState(null);
    const [isLoading, setIsLoading] = React.useState(false);
    // Generate preview before execution (when no result)
    React.useEffect(() => {
        if (!result && !preview && !isLoading) {
            const generatePreview = async () => {
                setIsLoading(true);
                try {
                    // Run the same logic to generate a preview
                    const previewResult = await executeGitCreatePR(args);
                    setPreview(previewResult);
                }
                catch {
                    // Silently fail on preview generation errors
                }
                finally {
                    setIsLoading(false);
                }
            };
            void generatePreview();
        }
    }, [result, preview, isLoading, args]);
    // Use either the actual result or the preview
    const displayResult = result || preview;
    // Parse result for display
    let title = '';
    let description = '';
    let targetBranch = args.targetBranch || 'main';
    let hasBreakingChanges = false;
    if (displayResult) {
        const titleMatch = displayResult.match(/--- Title ---\n(.+)/);
        if (titleMatch)
            title = titleMatch[1];
        // Extract description (between --- Description --- and the end or next section)
        const descMatch = displayResult.match(/--- Description ---\n([\s\S]*?)(?:\n---|\n\nTo create|$)/);
        if (descMatch) {
            // Get first few lines of description for preview
            const descLines = descMatch[1].trim().split('\n').slice(0, 5);
            description = descLines.join('\n');
            if (descMatch[1].trim().split('\n').length > 5) {
                description += '\n...';
            }
        }
        const branchMatch = displayResult.match(/Branch: .+ -> (.+)/);
        if (branchMatch)
            targetBranch = branchMatch[1];
        hasBreakingChanges = displayResult.includes('Breaking Changes');
    }
    const messageContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.tool, children: "\u2692 git_create_pr" }), _jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Target: " }), _jsx(Text, { color: colors.primary, children: targetBranch })] }), isLoading && (_jsx(Box, { children: _jsx(Text, { color: colors.secondary, children: "Generating preview..." }) })), args.draft && (_jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Draft: " }), _jsx(Text, { color: colors.text, children: "Yes" })] })), title && (_jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Title: " }), _jsx(Text, { color: colors.text, children: title.length > 40 ? title.substring(0, 40) + '...' : title })] })), description && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.secondary, children: "Description:" }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: colors.text, children: description }) })] })), hasBreakingChanges && (_jsx(Box, { children: _jsx(Text, { color: colors.error, children: "Contains breaking changes!" }) }))] }));
    return _jsx(ToolMessage, { message: messageContent, hideBox: true });
});
const formatter = (args, result) => {
    return _jsx(GitCreatePRFormatter, { args: args, result: result });
};
const validator = async (args) => {
    // Check if in git repository
    if (!(await isGitRepository())) {
        return {
            valid: false,
            error: 'git Not in a git repository',
        };
    }
    // Check if not on default branch
    const currentBranch = await getCurrentBranch();
    const defaultBranch = await getDefaultBranch();
    const targetBranch = args.targetBranch || defaultBranch;
    if (currentBranch === targetBranch) {
        return {
            valid: false,
            error: `git Currently on ${targetBranch}. Switch to a feature branch first.`,
        };
    }
    return { valid: true };
};
// Export the tool using NanocoderToolExport pattern
export const gitCreatePRTool = {
    name: 'git_create_pr',
    tool: gitCreatePRCoreTool,
    formatter,
    validator,
};
//# sourceMappingURL=git-create-pr.js.map