generateMethodCode function

void generateMethodCode(
  1. String feature,
  2. String httpMethod,
  3. String method,
  4. String model,
  5. bool pagination,
  6. bool store,
  7. String? json,
  8. String? queryClassName,
  9. String? queryJson,
)

Implementation

void generateMethodCode(
  String feature,
  String httpMethod,
  String method,
  String model,
  bool pagination,
  bool store,
  String? json,
  String? queryClassName,
  String? queryJson,
) {
  final blocFile = File('$feature/presentation/bloc/${feature}_bloc.dart');
  if (!blocFile.existsSync()) {
    print('โŒ Bloc file not found for feature: $feature');
    return;
  }
  final eventFile = File('$feature/presentation/bloc/${feature}_event.dart');
  final stateFile = File('$feature/presentation/bloc/${feature}_state.dart');
  final repoFile = File('$feature/domain/repo/${feature}_repository.dart');
  final repoImplFile = File('$feature/data/repo_impl/${feature}_repo_impl.dart');
  final remoteFile = File('$feature/data/sources/${feature}_remote_source.dart');
  final endpointFile = File('$feature/data/endpoints/${feature}_endpoints.dart');

  final queryType = (queryClassName != null && queryClassName.trim().isNotEmpty)
      ? _capitalize(queryClassName.trim())
      : 'Fetch${_capitalize(feature)}Query';
  final modelType = _capitalize(model.trim().isEmpty ? '${feature}Response' : model.trim());

  final methodCode = '''
Future<void> _on${_capitalize(method)}(${_capitalize(method)}Requested event, Emitter<${_capitalize(feature)}State> emit) async {
  emit(state.copyWith(${method}Status: AppStatus.loading));

  final response = await _${feature}Repository.$method(
    queryParam: event.queryParam${httpMethod.toLowerCase() == 'post' || httpMethod.toLowerCase() == 'postmultipart' ? ', payload: event.payload' : ''}
  );
  response.fold(
    (error) => emit(state.copyWith(${method}Status: AppStatus.failure, error: error)),
    (result) async {
      emit(state.copyWith(
        ${method}Status: AppStatus.success${store ? ', ${_inferStoreVar(method)}: result.data' : ''}${pagination ? ', ${method}NextPage: result.pagination?.currentPage ?? 0, ${method}OffSet: result.pagination?.offSet ?? 0, ${method}TotalPage: result.pagination?.totalPage ?? 0' : ''}
      ));
    },
  );

  emit(state.copyWith(${method}Status: AppStatus.complete));
}
''';

  // Register handler in bloc constructor
  var blocContent = blocFile.readAsStringSync();
  final registrationLine = 'on<${_capitalize(method)}Requested>(_on${_capitalize(method)});';
  if (!blocContent.contains(registrationLine)) {
    final fetchHandlerRegExp = RegExp('on<${_capitalize(feature)}Fetched>\\(.*\\);');
    final match = fetchHandlerRegExp.firstMatch(blocContent);
    if (match != null) {
      blocContent = '${blocContent.substring(0, match.end)}\n    $registrationLine${blocContent.substring(match.end)}';
    }
  }
  if (!blocContent.contains(methodCode)) {
    blocContent = '$blocContent\n$methodCode';
  }
  blocFile.writeAsStringSync(blocContent, flush: true);
  print('โœ… Method $method added and registered in ${feature}_bloc.dart');

  // Also add AppStatus field for this method into the state
  if (stateFile.existsSync()) {
    var content = stateFile.readAsStringSync();

    if (!content.contains('final AppStatus ${method}Status')) {
      content = content.replaceFirst(
        'final AppStatus fetchStatus;',
        'final AppStatus fetchStatus;\n  final AppStatus ${method}Status;${store ? '\n  final dynamic ${_inferStoreVar(method)};' : ''}${pagination ? '\n  final int ${method}NextPage;\n  final int ${method}OffSet;\n  final int ${method}TotalPage;' : ''}',
      );

      content = content.replaceFirst(
        'const ${_capitalize(feature)}State({',
        'const ${_capitalize(feature)}State({\n    this.${method}Status = AppStatus.initial,${store ? '\n    this.${_inferStoreVar(method)},' : ''}${pagination ? '\n    this.${method}NextPage = 0,\n    this.${method}OffSet = 0,\n    this.${method}TotalPage = 0,' : ''}',
      );

      content = content.replaceFirst(
        '${_capitalize(feature)}State copyWith({',
        '${_capitalize(feature)}State copyWith({\n    AppStatus? ${method}Status,${store ? '\n    dynamic ${_inferStoreVar(method)},' : ''}${pagination ? '\n    int? ${method}NextPage,\n    int? ${method}OffSet,\n    int? ${method}TotalPage,' : ''}',
      );

      content = content.replaceFirst(
        'fetchStatus: fetchStatus ?? this.fetchStatus,',
        'fetchStatus: fetchStatus ?? this.fetchStatus,\n      ${method}Status: ${method}Status ?? this.${method}Status,${store ? '\n      ${_inferStoreVar(method)}: ${_inferStoreVar(method)} ?? this.${_inferStoreVar(method)},' : ''}${pagination ? '\n      ${method}NextPage: ${method}NextPage ?? this.${method}NextPage,\n      ${method}OffSet: ${method}OffSet ?? this.${method}OffSet,\n      ${method}TotalPage: ${method}TotalPage ?? this.${method}TotalPage,' : ''}',
      );

      content = content.replaceFirst(
        'List<Object?> get props => <Object?>[fetchStatus,',
        'List<Object?> get props => <Object?>[fetchStatus, ${method}Status,${store ? ' ${_inferStoreVar(method)},' : ''}${pagination ? ' ${method}NextPage, ${method}OffSet, ${method}TotalPage,' : ''}',
      );
    }

    stateFile.writeAsStringSync(content, flush: true);
    print('๐Ÿ”ง Updated ${feature}_state.dart with ${method}Status field.');
  }

  // Add new event for this method
  if (eventFile.existsSync()) {
    var content = eventFile.readAsStringSync();
    final eventClass = '''
class ${_capitalize(method)}Requested extends ${_capitalize(feature)}Event {
  const ${_capitalize(method)}Requested({
    this.queryParam,${httpMethod.toLowerCase() == 'post' || httpMethod.toLowerCase() == 'postmultipart' ? '\n    this.payload,' : ''}
  });

  final $queryType? queryParam;${httpMethod.toLowerCase() == 'post' || httpMethod.toLowerCase() == 'postmultipart' ? '\n  final Map<String, dynamic>? payload;' : ''}

  @override
  List<Object?> get props => <Object?>[queryParam${httpMethod.toLowerCase() == 'post' || httpMethod.toLowerCase() == 'postmultipart' ? ', payload' : ''}];
}
''';
    if (!content.contains('class ${_capitalize(method)}Requested')) {
      content = '$content\n$eventClass';
      eventFile.writeAsStringSync(content, flush: true);
      print('๐Ÿงฉ Added ${_capitalize(method)}Requested event.');
    }
  }

  // Append repository abstract method
  if (repoFile.existsSync()) {
    var content = repoFile.readAsStringSync();
    final modelImport = "import '../../data/model/response/${_snake(modelType)}.dart';";
    if (!content.contains(modelImport)) {
      content = '$modelImport\n$content';
    }
    final repoMethodSig = httpMethod.toLowerCase() == 'get'
        ? '  Future<Either<Failure, $modelType>> $method({$queryType? queryParam});'
        : '  Future<Either<Failure, $modelType>> $method({$queryType? queryParam, Map<String, dynamic>? payload});';
    if (!content.contains('$method(')) {
      final idx = content.lastIndexOf('}');
      final updated = '${content.substring(0, idx)}\n$repoMethodSig\n${content.substring(idx)}';
      repoFile.writeAsStringSync(updated, flush: true);
      print('๐Ÿ“„ Updated ${feature}_repository.dart with $method signature.');
    }
  }

  // Append repo_impl forwarding method
  if (repoImplFile.existsSync()) {
    var content = repoImplFile.readAsStringSync();
    final modelImport = "import '../../data/model/response/${_snake(modelType)}.dart';";
    if (!content.contains(modelImport)) {
      content = '$modelImport\n$content';
    }
    final implMethod = httpMethod.toLowerCase() == 'get'
        ? '''
  @override
  Future<Either<Failure, $modelType>> $method({
    $queryType? queryParam,
  }) {
    return _${feature}RemoteSource.$method(queryParam: queryParam);
  }
'''
        : '''
  @override
  Future<Either<Failure, $modelType>> $method({
    $queryType? queryParam,
    Map<String, dynamic>? payload,
  }) {
    return _${feature}RemoteSource.$method(queryParam: queryParam, payload: payload);
  }
''';
    if (!content.contains(' $method(')) {
      final idx = content.lastIndexOf('}');
      final updated = '${content.substring(0, idx)}\n$implMethod${content.substring(idx)}';
      repoImplFile.writeAsStringSync(updated, flush: true);
      print('๐Ÿ”— Updated ${feature}_repo_impl.dart with $method forwarding.');
    }
  }

  // Append remote source method using ApiClient
  if (remoteFile.existsSync()) {
    var content = remoteFile.readAsStringSync();
    final modelImport = "import '../../data/model/response/${_snake(modelType)}.dart';";
    if (!content.contains(modelImport)) {
      content = '$modelImport\n$content';
    }
    final endpointCall = '${_capitalize(feature)}Endpoints.$method(workspaceId: workspaceId)';
    final remoteMethod = () {
      final header = '''
  Future<Either<Failure, $modelType>> $method({
    $queryType? queryParam,${httpMethod.toLowerCase() == 'post' || httpMethod.toLowerCase() == 'postmultipart' ? '\n    Map<String, dynamic>? payload,' : ''}
  }) async {
    final workspaceId = await _secureStorageService.getWorkspaceId;
    if (workspaceId == null) {
      return const Left(GeneralFailure('Workspace ID not found'));
    }
    final apiEndpoint = $endpointCall;
''';
      final tail = '''
    return response.fold(
      Left.new,
      (result) => Right(${_camel(modelType)}FromJson(result)),
    );
  }
''';
      switch (httpMethod.toLowerCase()) {
        case 'get':
          return '$header    final response = await _apiClient.get<Map<String, dynamic>>(apiEndpoint, queryParams: queryParam?.toJson());\n$tail';
        case 'post':
          return '$header    final response = await _apiClient.post<Map<String, dynamic>>(apiEndpoint, queryParams: queryParam?.toJson(), payload: payload);\n$tail';
        case 'postmultipart':
          return '$header    final response = await _apiClient.postMultipart<Map<String, dynamic>>(apiEndpoint, queryParams: queryParam?.toJson(), payload: payload);\n$tail';
        default:
          return '$header    final response = await _apiClient.get<Map<String, dynamic>>(apiEndpoint, queryParams: queryParam?.toJson());\n$tail';
      }
    }();
    if (!content.contains(' $method(')) {
      final idx = content.lastIndexOf('}');
      final updated = '${content.substring(0, idx)}\n$remoteMethod${content.substring(idx)}';
      remoteFile.writeAsStringSync(updated, flush: true);
      print('๐ŸŒ Updated ${feature}_remote_source.dart with ${httpMethod.toUpperCase()} $method.');
    }
  }

  // Append endpoint stub for the method
  if (endpointFile.existsSync()) {
    final content = endpointFile.readAsStringSync();
    final endpointStub = '''
  static String $method({required String workspaceId}) => '\$_workspace/\$workspaceId/${feature}s';
''';
    if (!content.contains(' $method(')) {
      final idx = content.lastIndexOf('}');
      final updated = '${content.substring(0, idx)}\n$endpointStub${content.substring(idx)}';
      endpointFile.writeAsStringSync(updated, flush: true);
      print('๐Ÿ›ฃ๏ธ  Updated ${feature}_endpoints.dart with $method endpoint stub.');
    }
  }
  // Create model file if needed
  if (modelType.isNotEmpty) {
    final modelDir = Directory('$feature/data/model/response');
    if (!modelDir.existsSync()) modelDir.createSync(recursive: true);
    final filePath = '$feature/data/model/response/${_snake(modelType)}.dart';
    final modelFile = File(filePath);
    if (!modelFile.existsSync()) {
      final content = '''
import 'package:equatable/equatable.dart';

$modelType ${_camel(modelType)}FromJson(Map<String, dynamic> data) => $modelType.fromJson(data);

class $modelType extends Equatable {
  const $modelType({
    this.message,
    this.data,
    this.pagination,
  });

  factory $modelType.fromJson(Map<String, dynamic> json) => $modelType(
        message: json['message'] as String?,
        data: json['data'],
        pagination: json['pagination'] != null ? Pagination.fromJson(json['pagination'] as Map<String, dynamic>) : null,
      );

  final String? message;
  final dynamic data;
  final Pagination? pagination;

  $modelType copyWith({
    String? message,
    dynamic data,
    Pagination? pagination,
  }) => $modelType(
        message: message ?? this.message,
        data: data ?? this.data,
        pagination: pagination ?? this.pagination,
      );

  @override
  List<Object?> get props => <Object?>[message, data, pagination];
}

class Pagination extends Equatable {
  const Pagination({
    this.currentPage,
    this.offSet,
    this.totalPage,
  });

  factory Pagination.fromJson(Map<String, dynamic> json) => Pagination(
        currentPage: json['currentPage'] as int?,
        offSet: json['offSet'] as int?,
        totalPage: json['totalPage'] as int?,
      );

  final int? currentPage;
  final int? offSet;
  final int? totalPage;

  Pagination copyWith({
    int? currentPage,
    int? offSet,
    int? totalPage,
  }) => Pagination(
        currentPage: currentPage ?? this.currentPage,
        offSet: offSet ?? this.offSet,
        totalPage: totalPage ?? this.totalPage,
      );

  @override
  List<Object?> get props => <Object?>[currentPage, offSet, totalPage];
}
''';
      modelFile.writeAsStringSync(content, flush: true);
      print('๐Ÿ“ฆ Created model $modelType at $filePath');
    }
  }

  // Append custom query class in feature_request.dart when provided
  if (queryClassName != null && queryClassName.trim().isNotEmpty) {
    final reqFile = File('$feature/data/model/request/${feature}_request.dart');
    if (reqFile.existsSync()) {
      var content = reqFile.readAsStringSync();
      final className = _capitalize(queryClassName.trim());
      if (!content.contains('class $className')) {
        final queryClass = '''
class $className {
  $className();

  Map<String, dynamic> toJson() {
    return <String, dynamic>{};
  }
}
''';
        content = '$content\n$queryClass';
        reqFile.writeAsStringSync(content, flush: true);
        print('๐Ÿงช Added custom query class $className in ${feature}_request.dart');
      }
    }
  }
}