/**
 * Rules Routes Module
 * Handles all Rules-related API endpoints
 */
import { readFileSync, existsSync, readdirSync, unlinkSync, promises as fsPromises } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { executeCliTool } from '../../tools/cli-executor.js';
import { SmartContentFormatter } from '../../tools/cli-output-converter.js';
import { loadProtocol, loadTemplate } from '../../tools/template-discovery.js';
/**
 * Parse rule frontmatter
 * @param {string} content
 * @returns {Object}
 */
function parseRuleFrontmatter(content) {
    const result = {
        paths: [],
        content: content
    };
    // Check for YAML frontmatter
    if (content.startsWith('---')) {
        const endIndex = content.indexOf('---', 3);
        if (endIndex > 0) {
            const frontmatter = content.substring(3, endIndex).trim();
            result.content = content.substring(endIndex + 3).trim();
            // Parse frontmatter lines
            const lines = frontmatter.split('\n');
            for (const line of lines) {
                const colonIndex = line.indexOf(':');
                if (colonIndex > 0) {
                    const key = line.substring(0, colonIndex).trim().toLowerCase();
                    const value = line.substring(colonIndex + 1).trim();
                    if (key === 'paths') {
                        // Parse as comma-separated or YAML array
                        result.paths = value.replace(/^\[|\]$/g, '').split(',').map(t => t.trim()).filter(Boolean);
                    }
                }
            }
        }
    }
    return result;
}
/**
 * Recursively scan rules directory for .md files
 * @param {string} dirPath
 * @param {string} location
 * @param {string} subdirectory
 * @returns {Object[]}
 */
function scanRulesDirectory(dirPath, location, subdirectory) {
    const rules = [];
    try {
        const entries = readdirSync(dirPath, { withFileTypes: true });
        for (const entry of entries) {
            const fullPath = join(dirPath, entry.name);
            if (entry.isFile() && entry.name.endsWith('.md')) {
                const content = readFileSync(fullPath, 'utf8');
                const parsed = parseRuleFrontmatter(content);
                rules.push({
                    name: entry.name,
                    paths: parsed.paths,
                    content: parsed.content,
                    location,
                    path: fullPath,
                    subdirectory: subdirectory || null
                });
            }
            else if (entry.isDirectory()) {
                // Recursively scan subdirectories
                const subRules = scanRulesDirectory(fullPath, location, subdirectory ? `${subdirectory}/${entry.name}` : entry.name);
                rules.push(...subRules);
            }
        }
    }
    catch (e) {
        // Ignore errors
    }
    return rules;
}
/**
 * Get rules configuration from project and user directories
 * @param {string} projectPath
 * @returns {Object}
 */
function getRulesConfig(projectPath) {
    const result = {
        projectRules: [],
        userRules: []
    };
    try {
        // Project rules: .claude/rules/
        const projectRulesDir = join(projectPath, '.claude', 'rules');
        if (existsSync(projectRulesDir)) {
            const rules = scanRulesDirectory(projectRulesDir, 'project', '');
            result.projectRules = rules;
        }
        // User rules: ~/.claude/rules/
        const userRulesDir = join(homedir(), '.claude', 'rules');
        if (existsSync(userRulesDir)) {
            const rules = scanRulesDirectory(userRulesDir, 'user', '');
            result.userRules = rules;
        }
    }
    catch (error) {
        console.error('Error reading rules config:', error);
    }
    return result;
}
/**
 * Find rule file in directory (including subdirectories)
 * @param {string} baseDir
 * @param {string} ruleName
 * @returns {string|null}
 */
function findRuleFile(baseDir, ruleName) {
    try {
        // Direct path
        const directPath = join(baseDir, ruleName);
        if (existsSync(directPath)) {
            return directPath;
        }
        // Search in subdirectories
        const entries = readdirSync(baseDir, { withFileTypes: true });
        for (const entry of entries) {
            if (entry.isDirectory()) {
                const subPath = findRuleFile(join(baseDir, entry.name), ruleName);
                if (subPath)
                    return subPath;
            }
        }
    }
    catch (e) {
        // Ignore errors
    }
    return null;
}
/**
 * Get single rule detail
 * @param {string} ruleName
 * @param {string} location - 'project' or 'user'
 * @param {string} projectPath
 * @returns {Object}
 */
function getRuleDetail(ruleName, location, projectPath) {
    try {
        const baseDir = location === 'project'
            ? join(projectPath, '.claude', 'rules')
            : join(homedir(), '.claude', 'rules');
        // Find the rule file (could be in subdirectory)
        const rulePath = findRuleFile(baseDir, ruleName);
        if (!rulePath) {
            return { error: 'Rule not found' };
        }
        const content = readFileSync(rulePath, 'utf8');
        const parsed = parseRuleFrontmatter(content);
        const normalizedBaseDir = baseDir.replace(/\\/g, '/').replace(/\/+$/, '');
        const normalizedRulePath = rulePath.replace(/\\/g, '/');
        const relativePath = normalizedRulePath.startsWith(`${normalizedBaseDir}/`)
            ? normalizedRulePath.slice(normalizedBaseDir.length + 1)
            : ruleName;
        const relativeParts = relativePath.split('/');
        const subdirectory = relativeParts.length > 1 ? relativeParts.slice(0, -1).join('/') : null;
        return {
            rule: {
                name: ruleName,
                paths: parsed.paths,
                content: parsed.content,
                location,
                path: rulePath,
                subdirectory
            }
        };
    }
    catch (error) {
        return { error: error instanceof Error ? error.message : String(error) };
    }
}
/**
 * Delete a rule
 * @param {string} ruleName
 * @param {string} location
 * @param {string} projectPath
 * @returns {Object}
 */
function deleteRule(ruleName, location, projectPath) {
    try {
        const baseDir = location === 'project'
            ? join(projectPath, '.claude', 'rules')
            : join(homedir(), '.claude', 'rules');
        const rulePath = findRuleFile(baseDir, ruleName);
        if (!rulePath) {
            return { error: 'Rule not found' };
        }
        unlinkSync(rulePath);
        return { success: true, ruleName, location };
    }
    catch (error) {
        return { error: error instanceof Error ? error.message : String(error) };
    }
}
/**
 * Infer rule context from file name and subdirectory for better prompt generation
 * @param {string} fileName - Rule file name
 * @param {string} subdirectory - Optional subdirectory path
 * @param {string} location - 'project' or 'user'
 * @returns {Object} Inferred context
 */
function inferRuleContext(fileName, subdirectory, location) {
    const normalizedName = fileName.replace(/\.md$/i, '').toLowerCase();
    const normalizedSubdir = (subdirectory || '').toLowerCase();
    // Rule category inference from file name and subdirectory
    const categories = {
        coding: ['coding', 'code', 'style', 'format', 'lint', 'convention'],
        testing: ['test', 'spec', 'jest', 'vitest', 'mocha', 'coverage'],
        security: ['security', 'auth', 'permission', 'access', 'secret', 'credential'],
        architecture: ['arch', 'design', 'pattern', 'structure', 'module', 'layer'],
        documentation: ['doc', 'comment', 'readme', 'jsdoc', 'api-doc'],
        performance: ['perf', 'performance', 'optimize', 'cache', 'memory'],
        workflow: ['workflow', 'ci', 'cd', 'deploy', 'build', 'release'],
        tooling: ['tool', 'cli', 'script', 'npm', 'yarn', 'pnpm'],
        error: ['error', 'exception', 'handling', 'logging', 'debug']
    };
    let inferredCategory = 'general';
    let inferredKeywords = [];
    for (const [category, keywords] of Object.entries(categories)) {
        for (const keyword of keywords) {
            if (normalizedName.includes(keyword) || normalizedSubdir.includes(keyword)) {
                inferredCategory = category;
                inferredKeywords = keywords;
                break;
            }
        }
        if (inferredCategory !== 'general')
            break;
    }
    // Scope inference from location
    const scopeHint = location === 'project'
        ? 'This rule applies to the current project only'
        : 'This rule applies globally to all projects';
    // Technology hints from file name
    const techPatterns = {
        typescript: ['ts', 'typescript', 'tsc'],
        javascript: ['js', 'javascript', 'node'],
        react: ['react', 'jsx', 'tsx', 'component'],
        vue: ['vue', 'vuex', 'pinia'],
        python: ['python', 'py', 'pip', 'poetry'],
        rust: ['rust', 'cargo', 'rs'],
        go: ['go', 'golang', 'mod'],
        java: ['java', 'maven', 'gradle', 'spring']
    };
    let inferredTech = null;
    for (const [tech, patterns] of Object.entries(techPatterns)) {
        if (patterns.some(p => normalizedName.includes(p) || normalizedSubdir.includes(p))) {
            inferredTech = tech;
            break;
        }
    }
    return {
        category: inferredCategory,
        keywords: inferredKeywords,
        scopeHint,
        technology: inferredTech,
        isConditional: normalizedSubdir.length > 0
    };
}
/**
 * Build structured prompt for rule generation
 * @param {Object} params
 * @returns {string} Structured prompt
 */
function buildStructuredRulePrompt(params) {
    const { description, fileName, subdirectory, location, context, enableReview } = params;
    // Build category-specific guidance
    const categoryGuidance = {
        coding: 'Focus on code style, naming conventions, and formatting rules. Include specific examples of correct and incorrect patterns.',
        testing: 'Emphasize test structure, coverage expectations, mocking strategies, and assertion patterns.',
        security: 'Highlight security best practices, input validation, authentication requirements, and sensitive data handling.',
        architecture: 'Define module boundaries, dependency rules, layer responsibilities, and design pattern usage.',
        documentation: 'Specify documentation requirements, comment styles, and API documentation standards.',
        performance: 'Address caching strategies, optimization guidelines, resource management, and performance metrics.',
        workflow: 'Define CI/CD requirements, deployment procedures, and release management rules.',
        tooling: 'Specify tool configurations, script conventions, and dependency management rules.',
        error: 'Define error handling patterns, logging requirements, and exception management.',
        general: 'Provide clear, actionable guidelines that Claude can follow consistently.'
    };
    const guidance = categoryGuidance[context.category] || categoryGuidance.general;
    // Build technology-specific hint
    const techHint = context.technology
        ? `\nTECHNOLOGY CONTEXT: This rule is for ${context.technology} development. Use ${context.technology}-specific best practices and terminology.`
        : '';
    // Build subdirectory context
    const subdirHint = subdirectory
        ? `\nORGANIZATION: This rule will be placed in the "${subdirectory}" subdirectory, indicating its category/scope.`
        : '';
    // Build review instruction if enabled
    const reviewInstruction = enableReview
        ? `\n\nAFTER GENERATION:
- Verify the rule is specific and actionable
- Check for ambiguous language that could be misinterpreted
- Ensure examples are clear and relevant
- Validate markdown formatting is correct`
        : '';
    return `PURPOSE: Generate a high-quality Claude Code memory rule that will guide Claude's behavior when working in this codebase
SUCCESS CRITERIA: The rule must be (1) specific and actionable, (2) include concrete examples, (3) avoid ambiguous language, (4) follow Claude Code rule format

TASK:
• Parse the user's description to identify core requirements
• Infer additional context from file name "${fileName}" and category "${context.category}"
• Generate structured markdown content with clear instructions
• Include DO and DON'T examples where appropriate
• ${context.isConditional ? 'Consider if frontmatter paths are needed for conditional activation' : 'Create as a global rule'}

MODE: write

RULE CATEGORY: ${context.category}
CATEGORY GUIDANCE: ${guidance}
${techHint}
${subdirHint}
SCOPE: ${context.scopeHint}

EXPECTED OUTPUT FORMAT:
\`\`\`markdown
${context.isConditional ? `---
paths: [specific/path/patterns/**/*]
---

` : ''}# Rule Title

Brief description of what this rule enforces.

## Guidelines

1. **First guideline** - Explanation
2. **Second guideline** - Explanation

## Examples

### ✅ Correct
\`\`\`language
// Good example
\`\`\`

### ❌ Incorrect
\`\`\`language
// Bad example
\`\`\`

## Exceptions

- When this rule may not apply
\`\`\`

USER DESCRIPTION:
${description}

FILE NAME: ${fileName}
${subdirectory ? `SUBDIRECTORY: ${subdirectory}` : ''}
${reviewInstruction}

RULES: $PROTO $TMPL | Generate ONLY the rule content in markdown | No additional commentary | Do NOT use any tools | Output raw markdown text directly | write=CREATE`;
}
/**
 * Build structured prompt for code extraction
 * @param {Object} params
 * @returns {string} Structured prompt
 */
function buildExtractPrompt(params) {
    const { extractScope, extractFocus, fileName, subdirectory, context } = params;
    const scope = extractScope || '**/*';
    const focus = extractFocus || 'naming conventions, error handling, code structure, patterns';
    return `PURPOSE: Extract and document coding conventions from the existing codebase to create a Claude Code memory rule
SUCCESS CRITERIA: The rule must reflect ACTUAL patterns found in the code, not theoretical best practices

TASK:
• Scan files matching "${scope}" for recurring patterns
• Identify ${focus.split(',').length} or more distinct conventions
• Document each pattern with real code examples from the codebase
• Create actionable rules based on observed practices
• Note any inconsistencies found (optional section)

MODE: analysis

ANALYSIS SCOPE: @${scope}
FOCUS AREAS: ${focus}

EXTRACTION STRATEGY:
1. **Pattern Recognition**: Look for repeated code structures, naming patterns, file organization
2. **Consistency Check**: Identify which patterns are consistently followed vs. occasionally violated
3. **Frequency Analysis**: Prioritize patterns that appear most frequently
4. **Context Awareness**: Consider why certain patterns are used (performance, readability, etc.)

EXPECTED OUTPUT FORMAT:
\`\`\`markdown
# ${fileName.replace(/\.md$/i, '')} Conventions

Conventions extracted from codebase analysis of \`${scope}\`.

## Naming Conventions

- **Pattern name**: Description with example
  \`\`\`language
  // Actual code from codebase
  \`\`\`

## Code Structure

- **Pattern name**: Description with example

## Error Handling

- **Pattern name**: Description with example

## Notes

- Any inconsistencies or variations observed
\`\`\`

FILE NAME: ${fileName}
${subdirectory ? `SUBDIRECTORY: ${subdirectory}` : ''}
INFERRED CATEGORY: ${context.category}

RULES: $PROTO $TMPL | Extract REAL patterns from code | Include actual code snippets as examples | Do NOT use any tools | Output raw markdown text directly | analysis=READ-ONLY`;
}
/**
 * Build review prompt for validating and improving generated rules
 * @param {string} content - Generated rule content to review
 * @param {string} fileName - Target file name
 * @param {Object} context - Inferred context
 * @returns {string} Review prompt
 */
function buildReviewPrompt(content, fileName, context) {
    return `PURPOSE: Review and improve a Claude Code memory rule for quality, clarity, and actionability
SUCCESS CRITERIA: Output an improved version that is (1) more specific, (2) includes better examples, (3) has no ambiguous language

TASK:
• Analyze the rule for clarity and specificity
• Check if guidelines are actionable (Claude can follow them)
• Verify examples are concrete and helpful
• Remove any ambiguous or vague language
• Ensure markdown formatting is correct
• Improve structure if needed
• Keep the core intent and requirements intact

MODE: write

REVIEW CRITERIA:
1. **Specificity**: Each guideline should be specific enough to follow without interpretation
2. **Actionability**: Guidelines should tell Claude exactly what to do or not do
3. **Examples**: Good and bad examples should be clearly different and illustrative
4. **Consistency**: Formatting and style should be consistent throughout
5. **Completeness**: All necessary aspects of the rule should be covered
6. **Conciseness**: No unnecessary verbosity or repetition

RULE CATEGORY: ${context.category}
FILE NAME: ${fileName}

ORIGINAL RULE CONTENT:
\`\`\`markdown
${content}
\`\`\`

EXPECTED OUTPUT:
- Output ONLY the improved rule content in markdown format
- Do NOT include any commentary, explanation, or meta-text
- If the original is already high quality, return it unchanged
- Preserve any frontmatter (---paths---) if present

RULES: $PROTO $TMPL | Output ONLY improved markdown content | No additional text | Do NOT use any tools | Output raw markdown text directly | write=CREATE`;
}
/**
 * Generate rule content via CLI tool
 * @param {Object} params
 * @param {string} params.generationType - 'description' | 'template' | 'extract'
 * @param {string} params.description - Rule description (for 'description' mode)
 * @param {string} params.templateType - Template type (for 'template' mode)
 * @param {string} params.extractScope - Scope pattern (for 'extract' mode)
 * @param {string} params.extractFocus - Focus areas (for 'extract' mode)
 * @param {string} params.fileName - Target file name
 * @param {string} params.location - 'project' or 'user'
 * @param {string} params.subdirectory - Optional subdirectory
 * @param {string} params.projectPath - Project root path
 * @param {boolean} params.enableReview - Optional: enable secondary review
 * @returns {Object}
 */
async function generateRuleViaCLI(params) {
    // Generate unique execution ID for tracking
    const executionId = `rule-gen-${params.fileName.replace('.md', '')}-${Date.now()}`;
    try {
        const { generationType, description, templateType, extractScope, extractFocus, fileName, location, subdirectory, projectPath, enableReview, broadcastToClients } = params;
        let prompt = '';
        let mode = 'analysis';
        let workingDir = projectPath;
        // Infer context from file name and subdirectory
        const context = inferRuleContext(fileName, subdirectory || '', location);
        // Build prompt based on generation type
        if (generationType === 'description') {
            mode = 'write';
            prompt = buildStructuredRulePrompt({
                description: description || '',
                fileName,
                subdirectory: subdirectory || '',
                location,
                context,
                enableReview
            });
        }
        else if (generationType === 'template') {
            mode = 'write';
            prompt = `PURPOSE: Generate Claude Code rule from template type
TASK: • Create rule based on ${templateType} template • Generate structured markdown content
MODE: write
EXPECTED: Complete rule content in markdown format following template structure
RULES: $PROTO $TMPL | Follow Claude Code rule format | Use ${templateType} template patterns | Do NOT use any tools | Output raw markdown text directly | write=CREATE

TEMPLATE TYPE: ${templateType}
FILE NAME: ${fileName}`;
        }
        else if (generationType === 'extract') {
            mode = 'analysis';
            prompt = buildExtractPrompt({
                extractScope: extractScope || '',
                extractFocus: extractFocus || '',
                fileName,
                subdirectory: subdirectory || '',
                context
            });
        }
        else {
            return { error: `Unknown generation type: ${generationType}` };
        }
        // Broadcast CLI_EXECUTION_STARTED event
        if (broadcastToClients) {
            broadcastToClients({
                type: 'CLI_EXECUTION_STARTED',
                payload: {
                    executionId,
                    tool: 'claude',
                    mode,
                    category: 'internal',
                    context: 'rule-generation',
                    fileName
                }
            });
        }
        // Create onOutput callback for real-time streaming
        const onOutput = broadcastToClients
            ? (unit) => {
                // CliOutputUnit handler: use SmartContentFormatter for intelligent formatting (never returns null)
                const content = SmartContentFormatter.format(unit.content, unit.type);
                broadcastToClients({
                    type: 'CLI_OUTPUT',
                    payload: {
                        executionId,
                        chunkType: unit.type,
                        data: content
                    }
                });
            }
            : undefined;
        // Build rulesEnv for $PROTO and $TMPL injection
        const templateName = generationType === 'extract'
            ? 'analysis-analyze-code-patterns'
            : 'universal-universal-rigorous-style';
        const rulesEnv = {
            PROTO: loadProtocol(mode),
            TMPL: loadTemplate(templateName)
        };
        // Execute CLI tool (Claude) with at least 10 minutes timeout
        const startTime = Date.now();
        const result = await executeCliTool({
            tool: 'claude',
            prompt,
            mode,
            cd: workingDir,
            timeout: 600000, // 10 minutes
            category: 'internal',
            id: executionId,
            rulesEnv
        }, onOutput);
        // Broadcast CLI_EXECUTION_COMPLETED event
        if (broadcastToClients) {
            broadcastToClients({
                type: 'CLI_EXECUTION_COMPLETED',
                payload: {
                    executionId,
                    success: result.success,
                    status: result.execution?.status || (result.success ? 'success' : 'error'),
                    duration_ms: Date.now() - startTime
                }
            });
        }
        if (!result.success) {
            return {
                error: `CLI execution failed: ${result.stderr || 'Unknown error'}`,
                stderr: result.stderr
            };
        }
        // Extract generated content - prefer parsedOutput (extracted text from stream JSON)
        let generatedContent = (result.parsedOutput || result.stdout || '').trim();
        // Remove markdown code block wrapper if present (e.g., ```markdown...```)
        if (generatedContent.startsWith('```markdown')) {
            generatedContent = generatedContent.replace(/^```markdown\s*\n?/, '').replace(/\n?```\s*$/, '');
        }
        else if (generatedContent.startsWith('```')) {
            generatedContent = generatedContent.replace(/^```\w*\s*\n?/, '').replace(/\n?```\s*$/, '');
        }
        if (!generatedContent) {
            return {
                error: 'CLI execution returned empty content',
                stdout: result.stdout,
                stderr: result.stderr
            };
        }
        // Optional review step - verify and improve the generated rule
        let reviewResult = null;
        if (enableReview) {
            const reviewPrompt = buildReviewPrompt(generatedContent, fileName, context);
            const reviewExecutionId = `${executionId}-review`;
            // Broadcast review CLI_EXECUTION_STARTED event
            if (broadcastToClients) {
                broadcastToClients({
                    type: 'CLI_EXECUTION_STARTED',
                    payload: {
                        executionId: reviewExecutionId,
                        tool: 'claude',
                        mode: 'write',
                        category: 'internal',
                        context: 'rule-review',
                        fileName
                    }
                });
            }
            // Create onOutput callback for review step
            const reviewOnOutput = broadcastToClients
                ? (unit) => {
                    // CliOutputUnit handler: use SmartContentFormatter for intelligent formatting (never returns null)
                    const content = SmartContentFormatter.format(unit.content, unit.type);
                    broadcastToClients({
                        type: 'CLI_OUTPUT',
                        payload: {
                            executionId: reviewExecutionId,
                            chunkType: unit.type,
                            data: content
                        }
                    });
                }
                : undefined;
            // Build rulesEnv for review step
            const reviewRulesEnv = {
                PROTO: loadProtocol('write'),
                TMPL: loadTemplate('universal-universal-rigorous-style')
            };
            const reviewStartTime = Date.now();
            const reviewExecution = await executeCliTool({
                tool: 'claude',
                prompt: reviewPrompt,
                mode: 'write',
                cd: workingDir,
                timeout: 300000, // 5 minutes for review
                category: 'internal',
                id: reviewExecutionId,
                rulesEnv: reviewRulesEnv
            }, reviewOnOutput);
            // Broadcast review CLI_EXECUTION_COMPLETED event
            if (broadcastToClients) {
                broadcastToClients({
                    type: 'CLI_EXECUTION_COMPLETED',
                    payload: {
                        executionId: reviewExecutionId,
                        success: reviewExecution.success,
                        status: reviewExecution.execution?.status || (reviewExecution.success ? 'success' : 'error'),
                        duration_ms: Date.now() - reviewStartTime
                    }
                });
            }
            if (reviewExecution.success) {
                let reviewedContent = (reviewExecution.parsedOutput || reviewExecution.stdout || '').trim();
                // Remove markdown code block wrapper if present
                if (reviewedContent.startsWith('```markdown')) {
                    reviewedContent = reviewedContent.replace(/^```markdown\s*\n?/, '').replace(/\n?```\s*$/, '');
                }
                else if (reviewedContent.startsWith('```')) {
                    reviewedContent = reviewedContent.replace(/^```\w*\s*\n?/, '').replace(/\n?```\s*$/, '');
                }
                // Only use reviewed content if it's valid and different
                if (reviewedContent.length > 50 && reviewedContent !== generatedContent) {
                    generatedContent = reviewedContent;
                    reviewResult = {
                        reviewed: true,
                        originalLength: (result.parsedOutput || result.stdout || '').trim().length,
                        reviewedLength: reviewedContent.length
                    };
                }
            }
        }
        // Create the rule using the generated content
        const createResult = await createRule({
            fileName,
            content: generatedContent,
            paths: [],
            location,
            subdirectory,
            projectPath
        });
        return {
            success: createResult.success || false,
            ...createResult,
            generatedContent,
            executionId: result.conversation?.id,
            review: reviewResult
        };
    }
    catch (error) {
        return { error: error instanceof Error ? error.message : String(error) };
    }
}
/**
 * Create a new rule
 * @param {Object} params
 * @param {string} params.fileName - Rule file name (must end with .md)
 * @param {string} params.content - Rule content (markdown)
 * @param {string[]} params.paths - Optional paths for conditional rule
 * @param {string} params.location - 'project' or 'user'
 * @param {string} params.subdirectory - Optional subdirectory path
 * @param {string} params.projectPath - Project root path
 * @returns {Object}
 */
async function createRule(params) {
    try {
        const { fileName, content, paths, location, subdirectory, projectPath } = params;
        // Validate file name
        if (!fileName || !fileName.endsWith('.md')) {
            return { error: 'File name must end with .md' };
        }
        // Build base directory
        const baseDir = location === 'project'
            ? join(projectPath, '.claude', 'rules')
            : join(homedir(), '.claude', 'rules');
        // Build target directory (with optional subdirectory)
        const targetDir = subdirectory
            ? join(baseDir, subdirectory)
            : baseDir;
        // Ensure target directory exists
        await fsPromises.mkdir(targetDir, { recursive: true });
        // Build complete file path
        const filePath = join(targetDir, fileName);
        // Check if file already exists
        if (existsSync(filePath)) {
            return { error: `Rule '${fileName}' already exists in ${location} location` };
        }
        // Build complete content with frontmatter if paths provided
        let completeContent = content;
        if (paths && paths.length > 0) {
            const frontmatter = `---
paths: [${paths.join(', ')}]
---

`;
            completeContent = frontmatter + content;
        }
        // Write rule file
        await fsPromises.writeFile(filePath, completeContent, 'utf8');
        return {
            success: true,
            fileName,
            location,
            path: filePath,
            subdirectory: subdirectory || null
        };
    }
    catch (error) {
        return { error: error instanceof Error ? error.message : String(error) };
    }
}
/**
 * Handle Rules routes
 * @returns true if route was handled, false otherwise
 */
export async function handleRulesRoutes(ctx) {
    const { pathname, url, req, res, initialPath, handlePostRequest, broadcastToClients } = ctx;
    // API: Get all rules
    if (pathname === '/api/rules') {
        const projectPathParam = url.searchParams.get('path') || initialPath;
        const rulesData = getRulesConfig(projectPathParam);
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(rulesData));
        return true;
    }
    // API: Get single rule detail
    if (pathname.startsWith('/api/rules/') && req.method === 'GET' && !pathname.endsWith('/rules/')) {
        const ruleName = decodeURIComponent(pathname.replace('/api/rules/', ''));
        const location = url.searchParams.get('location') || 'project';
        const projectPathParam = url.searchParams.get('path') || initialPath;
        const ruleDetail = getRuleDetail(ruleName, location, projectPathParam);
        if (ruleDetail.error) {
            res.writeHead(404, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(ruleDetail));
        }
        else {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(ruleDetail));
        }
        return true;
    }
    // API: Delete rule
    if (pathname.startsWith('/api/rules/') && req.method === 'DELETE') {
        const ruleName = decodeURIComponent(pathname.replace('/api/rules/', ''));
        handlePostRequest(req, res, async (body) => {
            const { location, projectPath: projectPathParam } = body;
            const resolvedLocation = typeof location === 'string' && location.trim().length > 0 ? location : 'project';
            const resolvedProjectPath = typeof projectPathParam === 'string' && projectPathParam.trim().length > 0 ? projectPathParam : initialPath;
            return deleteRule(ruleName, resolvedLocation, resolvedProjectPath);
        });
        return true;
    }
    // API: Create rule
    if (pathname === '/api/rules/create' && req.method === 'POST') {
        handlePostRequest(req, res, async (body) => {
            const { mode, fileName, content, paths, location, subdirectory, projectPath: projectPathParam, generationType, description, templateType, extractScope, extractFocus } = body;
            const resolvedMode = typeof mode === 'string' ? mode : '';
            const resolvedFileName = typeof fileName === 'string' ? fileName : '';
            const resolvedContent = typeof content === 'string' ? content : '';
            const resolvedLocation = typeof location === 'string' && location.trim().length > 0 ? location : '';
            const resolvedSubdirectory = typeof subdirectory === 'string' ? subdirectory : '';
            const resolvedProjectPath = typeof projectPathParam === 'string' && projectPathParam.trim().length > 0 ? projectPathParam : initialPath;
            const resolvedGenerationType = typeof generationType === 'string' ? generationType : '';
            const resolvedDescription = typeof description === 'string' ? description : undefined;
            const resolvedTemplateType = typeof templateType === 'string' ? templateType : undefined;
            const resolvedExtractScope = typeof extractScope === 'string' ? extractScope : undefined;
            const resolvedExtractFocus = typeof extractFocus === 'string' ? extractFocus : undefined;
            const resolvedPaths = Array.isArray(paths) ? paths.filter((p) => typeof p === 'string') : [];
            if (!resolvedFileName) {
                return { error: 'File name is required' };
            }
            if (!resolvedLocation) {
                return { error: 'Location is required (project or user)' };
            }
            const projectPath = resolvedProjectPath;
            // CLI generation mode
            if (resolvedMode === 'cli-generate') {
                if (!resolvedGenerationType) {
                    return { error: 'generationType is required for CLI generation mode' };
                }
                // Validate based on generation type
                if (resolvedGenerationType === 'description' && !resolvedDescription) {
                    return { error: 'description is required for description-based generation' };
                }
                if (resolvedGenerationType === 'template' && !resolvedTemplateType) {
                    return { error: 'templateType is required for template-based generation' };
                }
                return await generateRuleViaCLI({
                    generationType: resolvedGenerationType,
                    description: resolvedDescription,
                    templateType: resolvedTemplateType,
                    extractScope: resolvedExtractScope,
                    extractFocus: resolvedExtractFocus,
                    fileName: resolvedFileName,
                    location: resolvedLocation,
                    subdirectory: resolvedSubdirectory || '',
                    projectPath,
                    broadcastToClients
                });
            }
            // Manual creation mode
            if (!resolvedContent) {
                return { error: 'Content is required for manual creation' };
            }
            return await createRule({
                fileName: resolvedFileName,
                content: resolvedContent,
                paths: resolvedPaths,
                location: resolvedLocation,
                subdirectory: resolvedSubdirectory || '',
                projectPath
            });
        });
        return true;
    }
    return false;
}
//# sourceMappingURL=rules-routes.js.map