run method

  1. @override
Future<int> run()
override

Runs the interactive project creation flow.

Implementation

@override
Future<int> run() async {
  // Read CLI options (may be null)
  final projectName = argResults?['name'] as String? ?? _promptForName();
  final org = argResults?['org'] as String;
  String? stateManagement = argResults?['state'] as String?; // nullable
  String? themeColor = argResults?['theme'] as String?; // nullable

  // Check if firebase flag was explicitly provided
  final firebaseFlagProvided = argResults?.wasParsed('firebase') ?? false;
  bool? includeFirebase =
      firebaseFlagProvided ? (argResults?['firebase'] as bool?) : null;

  // Check if web flag was explicitly provided
  final webFlagProvided = argResults?.wasParsed('web') ?? false;
  bool? includeWeb = webFlagProvided ? (argResults?['web'] as bool?) : null;

  // Check if docker flag was explicitly provided
  final dockerFlagProvided = argResults?.wasParsed('docker') ?? false;
  bool? includeDocker =
      dockerFlagProvided ? (argResults?['docker'] as bool?) : null;

  // Non-interactive flags
  final nonInteractive = (argResults?['yes'] as bool) == true ||
      (argResults?['no-interactive'] as bool) == true;

  if (!_isValidProjectName(projectName)) {
    logger.err('Invalid project name. Use lowercase with underscores.');
    return 1;
  }

  // Allowed options
  final allowedStates = ['provider', 'riverpod', 'bloc'];
  final allowedThemes = ['blue', 'green', 'coffee', 'purple', 'orange'];

  // Prompt for state management only if not provided and interactive allowed
  if (stateManagement == null) {
    if (!nonInteractive) {
      stateManagement = logger.chooseOne(
        '🔧 Choose state management:',
        choices: allowedStates,
        defaultValue: 'riverpod',
      );
    } else {
      stateManagement = 'riverpod';
      logger.detail(
          'No state provided; defaulting to "riverpod" in non-interactive mode.');
    }
  } else {
    if (!allowedStates.contains(stateManagement)) {
      logger.err('Invalid --state value. Allowed: provider, riverpod, bloc');
      return 1;
    }
  }

  // Prompt for theme color only if not provided and interactive allowed
  if (themeColor == null) {
    if (!nonInteractive) {
      themeColor = logger.chooseOne(
        '🎨 Choose your theme color:',
        choices: allowedThemes,
        defaultValue: 'blue',
      );
    } else {
      themeColor = 'blue';
      logger.detail(
          'No theme provided; defaulting to "blue" in non-interactive mode.');
    }
  } else {
    if (!allowedThemes.contains(themeColor)) {
      logger.err(
          'Invalid --theme value. Allowed: blue, green, coffee, purple, orange');
      return 1;
    }
  }

  // Prompt for authentication type
  String authType;
  if (!nonInteractive) {
    logger.info('');
    authType = logger.chooseOne(
      '🔐 Choose authentication type:',
      choices: [
        'email_password - Email & Password',
        'username_password - Username & Password',
        'phone_otp - Phone Number & OTP',
        'social_auth - Google & Apple Sign-In',
        'all - All authentication methods',
      ],
      defaultValue: 'email_password - Email & Password',
    );
    // Extract the key before the dash
    authType = authType.split(' ').first;
  } else {
    authType = 'email_password';
    logger.detail(
        'No auth type provided; defaulting to "email_password" in non-interactive mode.');
  }

  // Prompt for Chatbot
  bool includeChatbot = false;
  if (!nonInteractive) {
    logger.info('');
    includeChatbot = logger.confirm(
      '🤖 Include AI Chatbot (Gemini)?',
      defaultValue: false,
    );
  }

  // Prompt for Firebase if not provided
  List<String> firebaseModules = [];
  if (includeFirebase == null && !nonInteractive) {
    logger.info('');
    includeFirebase = logger.confirm(
      '🔥 Include Firebase?',
      defaultValue: false,
    );

    if (includeFirebase) {
      // Ask which Firebase modules to include
      logger.info('');
      final selectedModules = <String>['auth - Authentication'];

      // Extract module keys
      firebaseModules =
          selectedModules.map((m) => m.split(' ').first).toList();

      // Core is always included if any module is selected
      if (firebaseModules.isNotEmpty && !firebaseModules.contains('core')) {
        firebaseModules.insert(0, 'core');
      }
    }
  } else if (includeFirebase == null) {
    includeFirebase = false;
    logger.detail(
        'Firebase not specified; defaulting to false in non-interactive mode.');
  } else if (includeFirebase) {
    // If Firebase enabled via flag, include all modules by default
    firebaseModules = ['core', 'auth', 'firestore', 'storage', 'fcm'];
  }

  // Prompt for Flutter Web support
  if (includeWeb == null && !nonInteractive) {
    logger.info('');
    includeWeb = logger.confirm(
      '🌐 Include Flutter Web support?',
      defaultValue: false,
    );
  } else if (includeWeb == null) {
    includeWeb = false;
    logger.detail(
        'Web support not specified; defaulting to false in non-interactive mode.');
  }

  // Prompt for Docker if Web is enabled and not provided
  if (includeDocker == null && !nonInteractive) {
    if (includeWeb) {
      logger.info('');
      includeDocker = logger.confirm(
        '🐳 Include Docker setup for Flutter Web deployment?',
        defaultValue: false,
      );
    } else {
      includeDocker = false;
    }
  } else if (includeDocker == null) {
    includeDocker = false;
    logger.detail(
        'Docker not specified; defaulting to false in non-interactive mode.');
  } else if (includeDocker == true && !includeWeb) {
    // Edge case: Docker flag provided but web not enabled
    logger.warn('⚠️  Docker is only applicable for Flutter Web deployment.');
    logger.warn('Enabling Flutter Web support automatically...');
    includeWeb = true;
  }

  // Handle non-interactive mode edge case
  if (nonInteractive && includeDocker && !includeWeb) {
    includeWeb = true;
    logger.detail('Docker requires web; auto-enabling Flutter Web.');
  }

  // Prompt for localization
  List<String> selectedLanguages = ['en']; // English is always included
  if (!nonInteractive) {
    logger.info('');
    final wantsLocalization = logger.confirm(
      '🌍 Enable multi-language support?',
      defaultValue: false,
    );

    if (wantsLocalization) {
      logger.info('');
      logger
          .info('Select additional languages (English is already included):');

      final availableLanguages = [
        'es - Spanish (Español)',
        'fr - French (Français)',
        'de - German (Deutsch)',
        'it - Italian (Italiano)',
        'pt - Portuguese (Português)',
        'ru - Russian (Русский)',
        'zh - Chinese (中文)',
        'ja - Japanese (日本語)',
        'ar - Arabic (العربية)',
        'hi - Hindi (हिन्दी)',
        'bn - Bengali (বাংলা)',
        'te - Telugu (తెలుగు)',
        'mr - Marathi (मराठी)',
        'ta - Tamil (தமிழ்)',
        'gu - Gujarati (ગુજરાતી)',
        'kn - Kannada (ಕನ್ನಡ)',
        'ml - Malayalam (മലയാളം)',
        'pa - Punjabi (ਪੰਜਾਬੀ)',
        'or - Odia (ଓଡ଼ିଆ)',
      ];

      final selected = logger.chooseAny(
        '📦 Select languages (space to select, enter to continue):',
        choices: availableLanguages,
        defaultValues: [],
      );

      // Extract language codes
      final langCodes = selected.map((s) => s.split(' ').first).toList();
      selectedLanguages.addAll(langCodes.cast<String>());
    }
  }

  // Utility Modules now handled by onboarding (all generated, toggled at runtime)
  final selectedModules = [
    'camera',
    'speech',
    'recorder',
    'call',
    'contacts',
    'location',
  ];

  // Show summary before proceeding
  if (!nonInteractive) {
    logger
      ..info('')
      ..info('📋 Project Summary:')
      ..info('  Name: $projectName')
      ..info('  Organization: $org')
      ..info('  State Management: $stateManagement')
      ..info('  Theme: ${_getThemeEmoji(themeColor!)} $themeColor')
      ..info('  Auth Type: ${_getAuthTypeDisplay(authType)}')
      ..info('  AI Chatbot: ${includeChatbot ? '🤖 Yes' : '✗ No'}')
      ..info('  Firebase: ${includeFirebase ? '🔥 Yes' : '✗ No'}')
      ..info('  Languages: 🌍 ${selectedLanguages.join(', ')}');

    if (includeWeb) {
      logger.info('  Flutter Web: 🌐 Yes');
      logger.info('  Docker: ${includeDocker ? '🐳 Yes' : '✗ No'}');
    } else {
      logger.info('  Flutter Web: ✗ No (Mobile-only)');
    }

    if (includeFirebase && firebaseModules.isNotEmpty) {
      logger.info('  Firebase Modules: ${firebaseModules.join(', ')}');
    }

    if (selectedModules.isNotEmpty) {
      logger
          .info('  Utility Modules: ${_formatModuleNames(selectedModules)}');
    }

    logger.info('');

    final confirm = logger.confirm(
      'Continue with these settings?',
      defaultValue: true,
    );

    if (!confirm) {
      logger.info('❌ Project creation cancelled');
      return 0;
    }
  }

  final progress = logger.progress('Creating Flutter app: $projectName');

  try {
    final generator = ProjectGenerator(
      projectName: projectName,
      organization: org,
      stateManagement: stateManagement!,
      includeFirebase: includeFirebase,
      firebaseModules: firebaseModules,
      includeChatbot: includeChatbot,
      includeDocker: includeDocker,
      includeWeb: includeWeb,
      selectedLanguages: selectedLanguages,
      themeColor: themeColor!,
      authType: authType,
      logger: logger,
      selectedModules: selectedModules,
    );

    await generator.generate(
      onBeforeFirebase: () {
        progress.cancel(); // or complete()
      },
    );

    progress.complete('Project created successfully!');

    logger
      ..info('')
      ..success('✨ Flutter app created: $projectName')
      ..success('🎨 Theme: ${_getThemeEmoji(themeColor)} $themeColor')
      ..success('🔐 Auth: ${_getAuthTypeDisplay(authType)}')
      ..success(
          '🤖 AI Chatbot: ${includeChatbot ? 'Enabled (Gemini)' : 'Disabled'}')
      ..success('🔥 Firebase: ${includeFirebase ? 'Enabled' : 'Disabled'}')
      ..success('🌍 Languages: ${selectedLanguages.join(', ')}');

    if (includeWeb) {
      logger.success('🌐 Flutter Web: Enabled');
      logger.success('🐳 Docker: ${includeDocker ? 'Enabled' : 'Disabled'}');
    } else {
      logger.success('🌐 Flutter Web: Disabled (Mobile-only)');
    }

    if (includeFirebase && firebaseModules.isNotEmpty) {
      logger.success('   Modules: ${firebaseModules.join(', ')}');
    }

    if (selectedModules.isNotEmpty) {
      logger.success(
          '   Utility Modules: ${_formatModuleNames(selectedModules)}');
    }

    logger
      ..info('')
      ..info('Next steps:')
      ..info('  1. cd $projectName');

    if (includeChatbot) {
      logger.info(
          '  2. Add your Gemini API key in lib/core/constants/app_constants.dart');
      logger.info('  3. flutter pub get');
      logger.info('  4. flutter run');
    } else {
      logger.info('  2. flutter pub get');
      logger.info('  3. flutter run');
    }

    if (includeWeb && includeDocker) {
      logger
        ..info('')
        ..info('🐳 Docker is ready for Flutter Web!')
        ..info('  • make build    - Build Docker image')
        ..info('  • make run      - Run production')
        ..info('  • make dev      - Development with hot-reload')
        ..info('  • See DOCKER.md for complete documentation');
    } else if (includeWeb && !includeDocker) {
      logger
        ..info('')
        ..info('🌐 Flutter Web Commands:')
        ..info('  • flutter run -d chrome    - Run in browser')
        ..info('  • flutter build web        - Build for production');
    }

    logger
      ..info('')
      ..info('📱 Your app includes:')
      ..info('  • Splash Screen with smooth transitions')
      ..info('  • Home Screen with stats and quick actions')
      ..info('  • Profile Screen with settings')
      ..info('  • ${_getAuthScreensDescription(authType)}')
      ..info('  • Light & Dark mode support')
      ..info('  • Responsive design for phones and tablets')
      ..info('  • Go Router navigation with deep linking')
      ..info('  • 12+ reusable widgets (cards, buttons, loaders, etc.)')
      ..info('  • Custom app bar & bottom navigation')
      ..info('  • Dialog & snackbar helpers');

    if (includeChatbot) {
      logger.info('  • AI Chatbot powered by Google Gemini');
      logger.info('  • Beautiful chat UI with message bubbles');
      logger.info('  • Real-time typing indicators');
      logger.info('  • BLoC state management for chat');
    }

    if (includeFirebase && firebaseModules.isNotEmpty) {
      logger.info('  • Firebase operations file (CRUD ready)');
      if (firebaseModules.contains('auth')) {
        logger.info('    - Authentication (sign up, sign in, profile)');
      }
      if (firebaseModules.contains('firestore')) {
        logger.info('    - Firestore (CRUD, queries, real-time streams)');
      }
      if (firebaseModules.contains('storage')) {
        logger.info('    - Storage (upload, download, delete files)');
      }
      if (firebaseModules.contains('fcm')) {
        logger.info('    - Cloud Messaging (push notifications)');
      }
    }

    if (selectedModules.isNotEmpty) {
      logger.info('  • Utility Modules:');
      if (selectedModules.contains('camera')) {
        logger.info('    - Camera service with permission handling');
      }
      if (selectedModules.contains('speech')) {
        logger.info('    - Speech-to-text with continuous listening');
        logger.info('    - Text-to-speech with multiple languages');
      }
      if (selectedModules.contains('recorder')) {
        logger.info('    - Audio recording with pause/resume');
      }
      if (selectedModules.contains('call')) {
        logger.info('    - Phone call functionality');
      }
    }

    if (includeWeb) {
      logger.info('  • Flutter Web build configuration');
      logger.info('  • Web-optimized assets and routing');

      if (includeDocker) {
        logger.info('  • Docker multi-stage build (Flutter + Nginx)');
        logger.info('  • Docker Compose for easy orchestration');
        logger.info('  • Production-ready with PostgreSQL & Redis');
        logger.info('  • Makefile for convenient commands');
        logger.info('  • GitHub Actions CI/CD workflow');
      }
    }

    if (selectedLanguages.length > 1) {
      logger.info(
          '  • Multi-language support (${selectedLanguages.length} languages)');
      logger.info('  • Language selector widget');
      logger.info('  • Persistent language preference');
      logger.info('  • RTL support for Arabic');
    }

    logger.info('');
    logger.info(
        'ℹ️  Note: Docker support is optional and applies only to Flutter Web builds.');
    logger.info(
        '   Mobile apps are deployed via Play Store / App Store as usual.');
    logger.info('');

    return 0;
  } catch (e, st) {
    progress.fail('Failed to create project');
    logger.err('Error: $e');
    logger.detail(st.toString());
    return 1;
  }
}