// override_manager.dart — Pillar 2: Override/customization layer with re-gen safety

import 'dart:io';
import 'package:path/path.dart' as p;
import 'models.dart';
import 'logger.dart';

const _customDir     = 'custom';
const _customMarker  = '# CURSOR:CUSTOM';
const _customEndMark = '# CURSOR:CUSTOM:END';

class OverrideManager {
  /// Snapshot the existing custom/ folder and CURSOR:CUSTOM blocks
  /// BEFORE any re-generation writes happen.
  static Future<OverrideSnapshot> snapshot(String outputDir) async {
    final customPath = p.join(outputDir, _customDir);
    final customFiles = <String>[];
    final customSections = <String, String>{};

    // 1. Snapshot custom/ folder
    final dir = Directory(customPath);
    if (dir.existsSync()) {
      await for (final entity in dir.list(recursive: true)) {
        if (entity is File) {
          customFiles.add(entity.path);
        }
      }
      Logger.dim('  Snapshotted ${customFiles.length} file(s) from custom/');
    }

    // 2. Snapshot CURSOR:CUSTOM sections from existing generated files
    final rulesDir = Directory(p.join(outputDir, 'rules'));
    if (rulesDir.existsSync()) {
      await for (final entity in rulesDir.list(recursive: true)) {
        if (entity is File && entity.path.endsWith('.mdc')) {
          final content = await entity.readAsString();
          final sections = _extractCustomSections(content);
          if (sections.isNotEmpty) {
            customSections[entity.path] = sections;
            Logger.dim('  Snapshotted ${_countSections(sections)} CURSOR:CUSTOM block(s) in ${p.basename(entity.path)}');
          }
        }
      }
    }

    return OverrideSnapshot(customFiles: customFiles, customSections: customSections);
  }

  /// Restore the custom/ folder after re-generation.
  /// The generator NEVER writes to custom/ — this just ensures it survives.
  static Future<void> restoreCustomFolder(OverrideSnapshot snapshot, String outputDir) async {
    if (snapshot.customFiles.isEmpty) return;

    final customPath = p.join(outputDir, _customDir);
    await Directory(customPath).create(recursive: true);

    // Write a README if it doesn't already exist
    final readme = File(p.join(customPath, 'README.md'));
    if (!readme.existsSync()) {
      await readme.writeAsString(_customReadme);
    }
    Logger.dim('  Custom folder preserved at ${customPath}');
  }

  /// Merge CURSOR:CUSTOM sections from existingContent into newContent.
  /// Any block between `# CURSOR:CUSTOM` and `# CURSOR:CUSTOM:END` in
  /// the existing file is transplanted into the newly rendered file.
  static String mergeCustomSections({
    required String newContent,
    required String existingContent,
  }) {
    final existingSections = _extractCustomSections(existingContent);
    if (existingSections.isEmpty) return newContent;

    // Append existing custom sections to the bottom of the new file
    // (if they don't already appear there)
    final buffer = StringBuffer(newContent.trimRight());
    buffer.writeln('\n');
    buffer.writeln('$_customMarker — preserved from previous version, do not delete this marker');
    buffer.writeln(existingSections);
    buffer.writeln(_customEndMark);
    return buffer.toString();
  }

  static String _extractCustomSections(String content) {
    final buffer = StringBuffer();
    bool inSection = false;
    for (final line in content.split('\n')) {
      if (line.trimLeft().startsWith(_customMarker)) {
        inSection = true;
        continue;
      }
      if (line.trimLeft().startsWith(_customEndMark)) {
        inSection = false;
        continue;
      }
      if (inSection) buffer.writeln(line);
    }
    return buffer.toString().trim();
  }

  static int _countSections(String sections) =>
      '\n'.allMatches(sections).length + 1;

  static const _customReadme = '''
# .cursor/custom/ — Your project-specific overrides

This directory is **NEVER touched by the generator**.
Anything you put here is preserved across all re-generations.

## How to use

### Override a generated rule
Create a file with the same name as a generated rule:
```
.cursor/custom/rules/bloc-cubit.mdc   ← overrides the generated version
```

### Add a project-only rule
Create any .mdc file:
```
.cursor/custom/rules/our-naming-convention.mdc
```

### CURSOR:CUSTOM inline blocks
Alternatively, in any generated .mdc file, add a block like:
```markdown
# CURSOR:CUSTOM
Your custom instructions here.
These lines are preserved on every --refresh.
# CURSOR:CUSTOM:END
```

The generator will detect and re-inject these blocks automatically.

## Examples
- `custom/rules/team-coding-style.mdc` — team-specific conventions
- `custom/rules/third-party-sdk.mdc` — rules for an internal SDK
- `custom/agents/internal-reviewer.mdc` — custom agent for your workflow
''';
}
