/**
 * Troubleshoot Grep Fallback
 * Searches markdown files for matching content when index doesn't find results
 */

import { readFileSync, readdirSync, existsSync } from 'fs';
import { join, dirname, basename } from 'path';
import { fileURLToPath } from 'url';
import { resolveStandardsDir } from '../stacks/stack-resolver.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const frameworkRoot = join(__dirname, '..', '..');

// Directories to search (stack standards resolved dynamically)
const SEARCH_PATHS = [
  'framework/standards',
  '.wiki'
];

function getSearchPaths(basePath) {
  const paths = [...SEARCH_PATHS];
  // Insert resolved stack standards path
  const stackStandards = resolveStandardsDir(basePath || frameworkRoot);
  const relativePath = stackStandards.replace(basePath || frameworkRoot, '').replace(/^[\\/]/, '');
  paths.splice(1, 0, relativePath);
  return paths;
}

/**
 * Get all markdown files from search paths
 * @param {string} basePath - Base path of the project
 * @returns {string[]} Array of file paths
 */
function getMarkdownFiles(basePath) {
  const files = [];

  for (const searchPath of getSearchPaths(basePath)) {
    const fullPath = join(basePath, searchPath);

    if (!existsSync(fullPath)) {
      continue;
    }

    try {
      const entries = readdirSync(fullPath, { withFileTypes: true });

      for (const entry of entries) {
        if (entry.isFile() && entry.name.endsWith('.md')) {
          files.push(join(fullPath, entry.name));
        }
      }
    } catch (error) {
      // Skip directories we can't read
    }
  }

  return files;
}

/**
 * Extract section containing the match
 * @param {string} content - File content
 * @param {number} matchIndex - Index of the match
 * @returns {Object} Section object with title and content
 */
function extractSection(content, matchIndex) {
  const lines = content.split('\n');
  let charCount = 0;
  let matchLineIndex = 0;

  // Find the line containing the match
  for (let i = 0; i < lines.length; i++) {
    charCount += lines[i].length + 1; // +1 for newline
    if (charCount > matchIndex) {
      matchLineIndex = i;
      break;
    }
  }

  // Find the section header (## heading) above the match
  let sectionTitle = 'Unknown Section';
  let sectionStart = 0;

  for (let i = matchLineIndex; i >= 0; i--) {
    if (lines[i].startsWith('## ')) {
      sectionTitle = lines[i].replace('## ', '').trim();
      sectionStart = i;
      break;
    }
  }

  // Find the end of the section (next ## or end of file)
  let sectionEnd = lines.length;
  for (let i = sectionStart + 1; i < lines.length; i++) {
    if (lines[i].startsWith('## ')) {
      sectionEnd = i;
      break;
    }
  }

  // Extract section content (limit to ~20 lines around match)
  const contextStart = Math.max(sectionStart, matchLineIndex - 10);
  const contextEnd = Math.min(sectionEnd, matchLineIndex + 10);
  const sectionContent = lines.slice(contextStart, contextEnd).join('\n');

  return {
    title: sectionTitle,
    content: sectionContent,
    lineNumber: matchLineIndex + 1
  };
}

/**
 * Search a file for keywords
 * @param {string} filePath - Path to the file
 * @param {string[]} keywords - Keywords to search for
 * @returns {Object[]} Array of matches
 */
function searchFile(filePath, keywords) {
  const matches = [];

  try {
    const content = readFileSync(filePath, 'utf-8');
    const contentLower = content.toLowerCase();

    for (const keyword of keywords) {
      const keywordLower = keyword.toLowerCase();
      let index = contentLower.indexOf(keywordLower);

      while (index !== -1) {
        const section = extractSection(content, index);

        // Check if we already have a match for this section
        const existingMatch = matches.find(m => m.section === section.title);

        if (existingMatch) {
          existingMatch.matchCount++;
          existingMatch.keywords.add(keyword);
        } else {
          matches.push({
            file: filePath,
            fileName: basename(filePath),
            section: section.title,
            content: section.content,
            lineNumber: section.lineNumber,
            matchCount: 1,
            keywords: new Set([keyword])
          });
        }

        index = contentLower.indexOf(keywordLower, index + 1);
      }
    }
  } catch (error) {
    // Skip files we can't read
  }

  return matches;
}

/**
 * Search all markdown files for keywords
 * @param {string[]} keywords - Keywords to search for
 * @param {Object} options - Search options
 * @returns {Object[]} Array of matches sorted by relevance
 */
export function searchGrep(keywords, options = {}) {
  // Determine base path
  const basePath = options.basePath || join(__dirname, '../..');

  const files = getMarkdownFiles(basePath);
  let allMatches = [];

  for (const file of files) {
    const matches = searchFile(file, keywords);
    allMatches = allMatches.concat(matches);
  }

  // Convert keywords Set to Array and calculate score
  const results = allMatches.map(match => ({
    ...match,
    keywords: Array.from(match.keywords),
    score: match.matchCount * 5 + match.keywords.size * 3,
    source: 'grep'
  }));

  // Sort by score (higher is better) and deduplicate
  const seen = new Set();
  const uniqueResults = results
    .sort((a, b) => b.score - a.score)
    .filter(r => {
      const key = `${r.file}:${r.section}`;
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });

  return uniqueResults.slice(0, 10); // Limit to top 10
}

export default {
  searchGrep
};
