import 'dart:io';

import 'package:oto/oto/commands/command.dart';
import 'package:oto/oto/commands/command_registry.dart';

class CommandCatalogEntry {
  final String command;
  final String category;
  final String dataModel;
  final String? samplePath;
  final bool hasSample;
  final bool sampleExists;

  const CommandCatalogEntry({
    required this.command,
    required this.category,
    required this.dataModel,
    required this.samplePath,
    required this.hasSample,
    required this.sampleExists,
  });

  Map<String, dynamic> toJson() => {
        'command': command,
        'category': category,
        'dataModel': dataModel,
        'samplePath': samplePath,
        'hasSample': hasSample,
        'sampleExists': sampleExists,
      };
}

class CommandCatalog {
  const CommandCatalog();

  List<CommandCatalogEntry> entries({String? category, String? command}) {
    registerAllCommands();
    final normalizedCategory = category?.toLowerCase();
    final normalizedCommand = command?.toLowerCase();
    final list = Command.specs.values.map(_entryFromSpec).where((entry) {
      final categoryMatches = normalizedCategory == null ||
          entry.category.toLowerCase() == normalizedCategory;
      final commandMatches = normalizedCommand == null ||
          entry.command.toLowerCase() == normalizedCommand;
      return categoryMatches && commandMatches;
    }).toList();
    list.sort((a, b) {
      final byCategory = a.category.compareTo(b.category);
      return byCategory == 0
          ? a.command.compareTo(b.command)
          : byCategory;
    });
    return List.unmodifiable(list);
  }

  CommandCatalogEntry _entryFromSpec(CommandSpec spec) {
    final sample = spec.samplePath;
    return CommandCatalogEntry(
      command: spec.type.name,
      category: spec.category,
      dataModel: spec.dataModel,
      samplePath: sample,
      hasSample: sample != null,
      sampleExists: sample != null && File(sample).existsSync(),
    );
  }
}
