/**
 * Server-side utilities for reading project documentation files.
 *
 * Scans the repo root for .md files in docs/, plus root-level READMEs etc.
 * New docs added to the repo auto-appear — no code changes needed.
 */

import fs from 'fs';
import path from 'path';

/** Resolve the repo root (two levels up from admin-dashboard-web/src/lib/) */
function getRepoRoot(): string {
  // In dev: process.cwd() is admin-dashboard-web/
  // DOCS_DIR env override for Docker/custom setups
  if (process.env.DOCS_DIR) return path.resolve(process.env.DOCS_DIR, '..');
  return path.resolve(process.cwd(), '..');
}

export interface DocFile {
  slug: string; // e.g. "docs/STRIPE_SETUP_GUIDE" or "README"
  title: string; // Human-readable title derived from filename
  path: string; // Relative path from repo root, e.g. "docs/STRIPE_SETUP_GUIDE.md"
  category: string; // e.g. "docs", "docs/research", "root"
  sizeBytes: number;
  modifiedAt: string; // ISO date
}

/** Derive a human-readable title from a filename */
function titleFromFilename(filename: string): string {
  return filename
    .replace(/\.md$/i, '')
    .replace(/[_-]/g, ' ')
    .replace(/\b\w/g, c => c.toUpperCase());
}

/** List all .md files in the repo that should be shown in the admin portal */
export function listDocs(): DocFile[] {
  const root = getRepoRoot();
  const results: DocFile[] = [];

  // 1. Root-level .md files
  const rootFiles = fs.readdirSync(root).filter(f => f.endsWith('.md'));
  for (const f of rootFiles) {
    const full = path.join(root, f);
    const stat = fs.statSync(full);
    results.push({
      slug: f.replace(/\.md$/i, ''),
      title: titleFromFilename(f),
      path: f,
      category: 'root',
      sizeBytes: stat.size,
      modifiedAt: stat.mtime.toISOString(),
    });
  }

  // 2. docs/ directory (recursive)
  const docsDir = path.join(root, 'docs');
  if (fs.existsSync(docsDir)) {
    walkDir(docsDir, root, results);
  }

  // 3. Service READMEs
  const serviceDirs = [
    'backend',
    'admin-dashboard-web',
    'user-dashboard-web',
    'mobile_app',
    'tracker-dashboard-web',
  ];
  for (const dir of serviceDirs) {
    const readme = path.join(root, dir, 'README.md');
    if (fs.existsSync(readme)) {
      const stat = fs.statSync(readme);
      results.push({
        slug: `${dir}/README`,
        title: `${dir} — README`,
        path: `${dir}/README.md`,
        category: 'services',
        sizeBytes: stat.size,
        modifiedAt: stat.mtime.toISOString(),
      });
    }
  }

  return results.sort((a, b) => a.path.localeCompare(b.path));
}

function walkDir(dir: string, repoRoot: string, results: DocFile[]): void {
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
    const full = path.join(dir, entry.name);
    if (entry.isDirectory()) {
      walkDir(full, repoRoot, results);
    } else if (entry.name.endsWith('.md')) {
      const rel = path.relative(repoRoot, full);
      const stat = fs.statSync(full);
      const category = path.dirname(rel);
      results.push({
        slug: rel.replace(/\.md$/i, ''),
        title: titleFromFilename(entry.name),
        path: rel,
        category,
        sizeBytes: stat.size,
        modifiedAt: stat.mtime.toISOString(),
      });
    }
  }
}

/** Read a single doc by its slug (e.g. "docs/STRIPE_SETUP_GUIDE") */
export function readDoc(slug: string): { content: string; meta: DocFile } | null {
  const root = getRepoRoot();
  const filePath = path.join(root, slug + '.md');

  // Security: prevent path traversal
  const resolved = path.resolve(filePath);
  if (!resolved.startsWith(path.resolve(root))) return null;

  if (!fs.existsSync(resolved)) return null;

  const stat = fs.statSync(resolved);
  const content = fs.readFileSync(resolved, 'utf-8');
  const rel = path.relative(root, resolved);

  return {
    content,
    meta: {
      slug,
      title: titleFromFilename(path.basename(rel)),
      path: rel,
      category: path.dirname(rel) === '.' ? 'root' : path.dirname(rel),
      sizeBytes: stat.size,
      modifiedAt: stat.mtime.toISOString(),
    },
  };
}

/** Full-text search across all docs (case-insensitive) */
export function searchDocs(query: string): Array<DocFile & { snippet: string }> {
  const docs = listDocs();
  const root = getRepoRoot();
  const results: Array<DocFile & { snippet: string }> = [];
  const lowerQuery = query.toLowerCase();

  for (const doc of docs) {
    const filePath = path.join(root, doc.path);
    if (!fs.existsSync(filePath)) continue;
    const content = fs.readFileSync(filePath, 'utf-8');
    const lowerContent = content.toLowerCase();
    const idx = lowerContent.indexOf(lowerQuery);
    if (idx !== -1) {
      const start = Math.max(0, idx - 80);
      const end = Math.min(content.length, idx + query.length + 80);
      const snippet =
        (start > 0 ? '...' : '') +
        content.slice(start, end).replace(/\n/g, ' ') +
        (end < content.length ? '...' : '');
      results.push({ ...doc, snippet });
    }
  }

  return results;
}

/** Gather all docs content for RAG context (truncated to stay within token limits) */
export function getAllDocsContent(maxCharsPerDoc = 4000): string {
  const docs = listDocs();
  const root = getRepoRoot();
  const parts: string[] = [];

  for (const doc of docs) {
    const filePath = path.join(root, doc.path);
    if (!fs.existsSync(filePath)) continue;
    let content = fs.readFileSync(filePath, 'utf-8');
    if (content.length > maxCharsPerDoc) {
      content = content.slice(0, maxCharsPerDoc) + '\n...(truncated)';
    }
    parts.push(`=== ${doc.path} ===\n${content}`);
  }

  return parts.join('\n\n');
}
