// @ts-nocheck
/**
 * Rules Routes Module
 * Handles all Rules-related API endpoints
 */
import type { IncomingMessage, ServerResponse } from 'http';
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';

export interface RouteContext {
  pathname: string;
  url: URL;
  req: IncomingMessage;
  res: ServerResponse;
  initialPath: string;
  handlePostRequest: (req: IncomingMessage, res: ServerResponse, handler: (body: unknown) => Promise<any>) => void;
  broadcastToClients: (data: unknown) => void;
}

/**
 * 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);

    return {
      rule: {
        name: ruleName,
        paths: parsed.paths,
        content: parsed.content,
        location,
        path: rulePath
      }
    };
  } catch (error) {
    return { error: (error as Error).message };
  }
}

/**
 * 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 as Error).message };
  }
}

/**
 * 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
 * @returns {Object}
 */
async function generateRuleViaCLI(params) {
  try {
    const {
      generationType,
      description,
      templateType,
      extractScope,
      extractFocus,
      fileName,
      location,
      subdirectory,
      projectPath
    } = params;

    let prompt = '';
    let mode = 'analysis';
    let workingDir = projectPath;

    // Build prompt based on generation type
    if (generationType === 'description') {
      mode = 'write';
      prompt = `PURPOSE: Generate Claude Code memory rule from description to guide Claude's behavior
TASK: • Analyze rule requirements • Generate markdown content with clear instructions
MODE: write
EXPECTED: Complete rule content in markdown format
RULES: $(cat ~/.claude/workflows/cli-templates/prompts/universal/00-universal-rigorous-style.txt) | Follow Claude Code rule format | Use frontmatter for conditional rules if paths specified | write=CREATE

RULE DESCRIPTION:
${description}

FILE NAME: ${fileName}`;
    } 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: $(cat ~/.claude/workflows/cli-templates/prompts/universal/00-universal-rigorous-style.txt) | Follow Claude Code rule format | Use ${templateType} template patterns | write=CREATE

TEMPLATE TYPE: ${templateType}
FILE NAME: ${fileName}`;
    } else if (generationType === 'extract') {
      mode = 'analysis';
      prompt = `PURPOSE: Extract coding rules from existing codebase to document patterns and conventions
TASK: • Analyze code patterns in specified scope • Extract common conventions • Identify best practices
MODE: analysis
CONTEXT: @${extractScope || '**/*'}
EXPECTED: Rule content based on codebase analysis with examples
RULES: $(cat ~/.claude/workflows/cli-templates/prompts/analysis/02-analyze-code-patterns.txt) | Focus on actual patterns found | Include code examples | analysis=READ-ONLY

ANALYSIS SCOPE: ${extractScope || '**/*'}
FOCUS AREAS: ${extractFocus || 'naming conventions, error handling, code structure'}`;
    } else {
      return { error: `Unknown generation type: ${generationType}` };
    }

    // Execute CLI tool (Claude) with at least 10 minutes timeout
    const result = await executeCliTool({
      tool: 'claude',
      prompt,
      mode,
      cd: workingDir,
      timeout: 600000, // 10 minutes
      category: 'internal'
    });

    if (!result.success) {
      return {
        error: `CLI execution failed: ${result.stderr || 'Unknown error'}`,
        stderr: result.stderr
      };
    }

    // Extract generated content from stdout
    const generatedContent = result.stdout.trim();

    if (!generatedContent) {
      return {
        error: 'CLI execution returned empty content',
        stdout: result.stdout,
        stderr: result.stderr
      };
    }

    // 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
    };
  } catch (error) {
    return { error: (error as Error).message };
  }
}

/**
 * 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 as Error).message };
  }
}

/**
 * Handle Rules routes
 * @returns true if route was handled, false otherwise
 */
export async function handleRulesRoutes(ctx: RouteContext): Promise<boolean> {
  const { pathname, url, req, res, initialPath, handlePostRequest } = 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;
      return deleteRule(ruleName, location, projectPathParam || initialPath);
    });
    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,
        // CLI generation parameters
        generationType,
        description,
        templateType,
        extractScope,
        extractFocus
      } = body;

      if (!fileName) {
        return { error: 'File name is required' };
      }

      if (!location) {
        return { error: 'Location is required (project or user)' };
      }

      const projectPath = projectPathParam || initialPath;

      // CLI generation mode
      if (mode === 'cli-generate') {
        if (!generationType) {
          return { error: 'generationType is required for CLI generation mode' };
        }

        // Validate based on generation type
        if (generationType === 'description' && !description) {
          return { error: 'description is required for description-based generation' };
        }

        if (generationType === 'template' && !templateType) {
          return { error: 'templateType is required for template-based generation' };
        }

        return await generateRuleViaCLI({
          generationType,
          description,
          templateType,
          extractScope,
          extractFocus,
          fileName,
          location,
          subdirectory: subdirectory || '',
          projectPath
        });
      }

      // Manual creation mode
      if (!content) {
        return { error: 'Content is required for manual creation' };
      }

      return await createRule({
        fileName,
        content,
        paths: paths || [],
        location,
        subdirectory: subdirectory || '',
        projectPath
      });
    });
    return true;
  }

  return false;
}
