// version_manager.dart — Pillar 1: Template versioning & update propagation

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

const _lockFileName = '.cursor-gen-lock.json';
const _currentVersion = '1.0.1';

class VersionManager {
  /// Check if the project's locked version differs from the current template version
  static Future<VersionStatus> check({required ProjectBrief brief}) async {
    final locked = brief.cursorTemplatesVersion ?? 'unset';
    final hasUpdate = locked != _currentVersion && locked != 'unset';
    return VersionStatus(
      hasUpdate: hasUpdate,
      currentVersion: locked,
      latestVersion: _currentVersion,
    );
  }

  /// Write the version lock file after successful generation
  static Future<void> writeLock({
    required String outputDir,
    required String briefPath,
    required ProjectBrief brief,
  }) async {
    final briefHash = await _fileHash(briefPath);
    final lock = {
      'templateVersion': _currentVersion,
      'generatedAt': DateTime.now().toIso8601String(),
      'briefHash': briefHash,
      'projectName': brief.projectName,
      'stack': {
        'stateManagement': brief.stateManagement,
        'architecture': brief.architecture,
        'routing': brief.routing,
        'backends': brief.backends,
        'platforms': brief.platforms,
        'codegenTools': brief.codegenTools,
      },
      'note': 'Auto-generated by cursor_gen. Do not edit manually. '
          'Run: cursor_gen --check-updates  to see available updates.',
    };
    final file = File(p.join(outputDir, _lockFileName));
    await file.parent.create(recursive: true);
    await file.writeAsString(const JsonEncoder.withIndent('  ').convert(lock));
  }

  /// Read the existing lock file
  static Future<Map<String, dynamic>?> readLock(String outputDir) async {
    final file = File(p.join(outputDir, _lockFileName));
    if (!file.existsSync()) return null;
    return jsonDecode(await file.readAsString()) as Map<String, dynamic>;
  }

  /// --check-updates: show detailed diff between locked and current version
  static Future<void> checkUpdates({required String briefPath}) async {
    final file = File(briefPath);
    if (!file.existsSync()) {
      Logger.error('project-brief.yaml not found at $briefPath');
      return;
    }
    final lock = await readLock('.cursor');
    if (lock == null) {
      Logger.warn('No lock file found. Run: cursor_gen  first.');
      return;
    }
    final lockedVersion = lock['templateVersion'] as String? ?? 'unknown';
    Logger.info('Template version check:');
    Logger.info('  Locked:  $lockedVersion');
    Logger.info('  Latest:  $_currentVersion');

    if (lockedVersion == _currentVersion) {
      Logger.success('  ✔ You are on the latest template version.');
    } else {
      Logger.warn('  ⚠ Update available!');
      Logger.info('\nTo update:');
      Logger.info(
          '  1. Update cursor_templates_version in project-brief.yaml to "$_currentVersion"');
      Logger.info('  2. Run: cursor_gen --diff   (preview changes)');
      Logger.info('  3. Run: cursor_gen --refresh (apply updates)');
      Logger.info(
          '\nChangelog: see CHANGELOG.md in flutter-cursor-templates repo');
    }
  }

  static Future<String> _fileHash(String path) async {
    final file = File(path);
    if (!file.existsSync()) return 'file-not-found';
    final bytes = await file.readAsBytes();
    return sha256.convert(bytes).toString().substring(0, 12);
  }
}
