/**
 * MORPH-SPEC Document Sharding
 * Splits large spec.md files into manageable shards (BMAD-inspired)
 * Achieves 90% token savings by loading only relevant sections
 */

import fs from 'fs';
import path from 'path';
import ora from 'ora';
import chalk from 'chalk';
import { logger } from '../utils/logger.js';
import { ensureDir, writeFile } from '../utils/file-copier.js';

// ============================================================================
// Helper Functions
// ============================================================================

function parseSpec(specContent) {
  const sections = [];
  const lines = specContent.split('\n');

  let currentSection = null;
  let currentContent = [];

  for (const line of lines) {
    // Detect level 2 heading (## Heading)
    if (line.match(/^## /)) {
      // Save previous section
      if (currentSection) {
        sections.push({
          title: currentSection,
          slug: toSlug(currentSection),
          content: currentContent.join('\n').trim(),
        });
      }

      // Start new section
      currentSection = line.replace(/^## /, '').trim();
      currentContent = [line]; // Include heading in content
    } else {
      currentContent.push(line);
    }
  }

  // Save last section
  if (currentSection) {
    sections.push({
      title: currentSection,
      slug: toSlug(currentSection),
      content: currentContent.join('\n').trim(),
    });
  }

  return sections;
}

function toSlug(title) {
  return title
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');
}

function generateIndex(sections, featureName) {
  let index = `# ${toTitleCase(featureName)} - Technical Specification\n\n`;
  index += `> **Sharded Spec:** This spec has been split into sections for optimal token usage\n`;
  index += `> **BMAD Pattern:** Load only the section you need during implementation\n\n`;
  index += `---\n\n`;
  index += `## 📋 Table of Contents\n\n`;

  sections.forEach((section, i) => {
    index += `${i + 1}. **[${section.title}](${section.slug}.md)**\n`;

    // Add first 100 chars as description
    const firstLine = section.content.split('\n').find(l => l.trim() && !l.startsWith('#'));
    const description = firstLine ? firstLine.substring(0, 100) + '...' : 'See section for details';
    index += `   > ${description}\n\n`;
  });

  index += `---\n\n`;
  index += `## 💡 How to Use Sharded Specs\n\n`;
  index += `### In Planning Phases (1-3)\n`;
  index += `Load **all sections** to get complete context:\n`;
  index += `\`\`\`bash\n`;
  index += `# Read index.md + all section files\n`;
  index += `\`\`\`\n\n`;

  index += `### In Implementation Phase (4)\n`;
  index += `Load **only the relevant section** for your current story:\n`;
  index += `\`\`\`bash\n`;
  index += `# Example: Working on entity design story\n`;
  index += `# Read: spec/index.md + spec/entity-design.md (not the other 10 sections!)\n`;
  index += `\`\`\`\n\n`;

  index += `**Token Savings:** For a 10-section spec (30k tokens), selective loading = **90% savings**\n\n`;
  index += `---\n\n`;
  index += `*Generated by MORPH-SPEC Framework - Document Sharding*\n`;
  index += `*Inspired by BMAD Method: 90% token reduction for large specs*\n`;

  return index;
}

function toTitleCase(str) {
  return str
    .split('-')
    .map(word => word.charAt(0).toUpperCase() + word.slice(1))
    .join(' ');
}

function estimateTokens(text) {
  // Rough estimate: 1 token ≈ 4 characters
  return Math.ceil(text.length / 4);
}

// ============================================================================
// Command Function
// ============================================================================

export async function shardSpecCommand(feature, options) {
  logger.header('MORPH-SPEC Document Sharding');
  logger.dim(`Feature: ${feature}`);
  logger.blank();

  const spinner = ora('Analyzing spec.md...').start();

  try {
    // Find spec.md
    const specPath = path.join(process.cwd(), `.morph/project/outputs/${feature}/spec.md`);
    if (!fs.existsSync(specPath)) {
      throw new Error(`Spec not found: ${specPath}`);
    }

    // Read spec content
    const specContent = fs.readFileSync(specPath, 'utf-8');
    const totalTokens = estimateTokens(specContent);

    spinner.info(`Original spec.md: ~${totalTokens.toLocaleString()} tokens`);
    logger.blank();

    // Parse into sections
    const sections = parseSpec(specContent);

    if (sections.length < 3) {
      spinner.warn(`Spec has only ${sections.length} sections - sharding not recommended`);
      logger.dim('  Sharding is most beneficial for specs with 5+ sections');
      return;
    }

    spinner.succeed(`Detected ${sections.length} sections`);
    logger.blank();

    // Generate index
    const indexContent = generateIndex(sections, feature);

    // Calculate savings
    const avgShardTokens = sections.reduce((sum, s) => sum + estimateTokens(s.content), 0) / sections.length;
    const savingsPercent = Math.round(((totalTokens - avgShardTokens) / totalTokens) * 100);

    logger.header('Token Savings (selective load):');
    logger.info(`  ${chalk.green(`~${savingsPercent}%`)} reduction`);
    logger.dim(`  - Full load: ~${totalTokens.toLocaleString()} tokens`);
    logger.dim(`  - Selective load: ~${Math.round(avgShardTokens).toLocaleString()} tokens (index + 1 shard)`);
    logger.blank();

    if (options.verbose) {
      logger.header('Shard Details:');
      logger.blank();
      sections.forEach((section, i) => {
        const tokens = estimateTokens(section.content);
        logger.dim(`  ${i + 1}. ${section.title}`);
        logger.dim(`     File: ${section.slug}.md`);
        logger.dim(`     Tokens: ~${tokens.toLocaleString()}`);
        logger.blank();
      });
    }

    // Output
    const outputDir = path.join(process.cwd(), `.morph/project/outputs/${feature}/spec`);

    if (options.dryRun) {
      logger.header('DRY RUN - Would create:');
      logger.dim(`  ${outputDir}/index.md`);
      sections.forEach(s => logger.dim(`  ${outputDir}/${s.slug}.md`));
      logger.blank();
      logger.success('Run without --dry-run to create files');
    } else {
      const createSpinner = ora('Creating sharded spec files...').start();

      // Create directory
      await ensureDir(outputDir);

      // Write index
      await writeFile(path.join(outputDir, 'index.md'), indexContent);
      createSpinner.text = 'Created index.md';

      // Write shards
      for (const section of sections) {
        const shardPath = path.join(outputDir, `${section.slug}.md`);
        await writeFile(shardPath, section.content);
        createSpinner.text = `Created ${section.slug}.md`;
      }

      createSpinner.succeed('Sharded spec created!');
      logger.blank();

      // Archive original spec.md
      const archivePath = specPath.replace('.md', '.original.md');
      fs.renameSync(specPath, archivePath);
      logger.dim('  Archived original: spec.original.md');
      logger.blank();

      logger.header('Next steps:');
      logger.dim(`  1. Review sharded spec in .morph/project/outputs/${feature}/spec/`);
      logger.dim(`  2. Create stories: morph-spec story create ${feature} SR-001`);
      logger.dim('  3. Stories will auto-load only relevant shards (90% token savings)');
      logger.blank();
    }

  } catch (error) {
    spinner.fail('Sharding failed');
    logger.error(error.message);
    process.exit(1);
  }
}
