/// Symbolic Evaluation Test File - Dart
///
/// This file contains multiple source→sink flows for testing symbolic evaluation.
/// Each section demonstrates dangerous (unsafe) and safe patterns.
///
/// Patterns covered:
/// - SQL injection (string interpolation vs parameterized)
/// - Command injection (Process.run)
/// - Path traversal (File operations)
/// - Shelf/HTTP request handling
/// - Null safety operators
/// - Future/async-await patterns
/// - Extension methods

import 'dart:io';
import 'dart:async';
import 'package:shelf/shelf.dart' as shelf;
import 'package:sqflite/sqflite.dart';

// =============================================================================
// DATA MODELS
// =============================================================================

class User {
  final String id;
  final String username;
  final String email;

  User({required this.id, required this.username, required this.email});

  factory User.fromMap(Map<String, dynamic> map) {
    return User(
      id: map['id'] as String,
      username: map['username'] as String,
      email: map['email'] as String,
    );
  }
}

// =============================================================================
// SQL INJECTION PATTERNS
// =============================================================================

class UserRepository {
  final Database db;

  UserRepository(this.db);

  // UNSAFE: String interpolation with user input
  Future<User?> getUserUnsafeInterpolation(String userId) async {
    final query = "SELECT * FROM users WHERE id = '$userId'";
    final results = await db.rawQuery(query);  // Sink: danger
    return results.isNotEmpty ? User.fromMap(results.first) : null;
  }

  // UNSAFE: String concatenation
  Future<User?> getUserUnsafeConcat(String username) async {
    final query = 'SELECT * FROM users WHERE username = \'' + username + '\'';
    final results = await db.rawQuery(query);  // Sink: danger
    return results.isNotEmpty ? User.fromMap(results.first) : null;
  }

  // UNSAFE: String multiplication/joining
  Future<User?> getUserUnsafeJoin(String email) async {
    final parts = ['SELECT * FROM users WHERE email = \'', email, '\''];
    final query = parts.join();
    final results = await db.rawQuery(query);  // Sink: danger
    return results.isNotEmpty ? User.fromMap(results.first) : null;
  }

  // SAFE: Parameterized query
  Future<User?> getUserSafeParameterized(String userId) async {
    final query = 'SELECT * FROM users WHERE id = ?';
    final results = await db.rawQuery(query, [userId]);  // Safe: parameterized
    return results.isNotEmpty ? User.fromMap(results.first) : null;
  }

  // SAFE: Constant query
  Future<List<User>> getAllUsersSafe() async {
    final query = 'SELECT * FROM users';
    final results = await db.rawQuery(query);  // Safe: constant
    return results.map((map) => User.fromMap(map)).toList();
  }
}

// =============================================================================
// COMMAND INJECTION PATTERNS
// =============================================================================

class CommandService {
  // UNSAFE: Process.run with shell command
  Future<String> executeUnsafeShell(String filename) async {
    final command = 'cat $filename';
    final result = await Process.run('sh', ['-c', command]);  // Sink: danger
    return result.stdout as String;
  }

  // UNSAFE: String interpolation in arguments
  Future<String> executeUnsafeInterpolation(String path) async {
    final result = await Process.run('sh', ['-c', 'ls $path']);  // Sink: danger
    return result.stdout as String;
  }

  // SAFE: Process.run with separate arguments
  Future<String> executeSafeArgs(String filename) async {
    final result = await Process.run('cat', [filename]);  // Safer: no shell
    return result.stdout as String;
  }

  // SAFE: Constant command
  Future<String> listDirectorySafe() async {
    final result = await Process.run('ls', ['-la']);  // Safe: constant
    return result.stdout as String;
  }
}

// =============================================================================
// FILE OPERATIONS PATTERNS
// =============================================================================

class FileService {
  final String basePath;

  FileService(this.basePath);

  // UNSAFE: String interpolation path
  Future<String> readFileUnsafeInterpolation(String filename) async {
    final path = '$basePath/$filename';
    final file = File(path);
    return await file.readAsString();  // Sink: path traversal
  }

  // UNSAFE: Path concatenation
  Future<String> readFileUnsafeConcat(String filename) async {
    final path = basePath + '/' + filename;
    final file = File(path);
    return await file.readAsString();  // Sink: danger
  }

  // SAFE: Validated path
  Future<String> readFileSafe(String filename) async {
    if (filename.contains('..') || filename.startsWith('/')) {
      throw ArgumentError('Invalid filename');
    }
    final path = '$basePath/$filename';
    final file = File(path);
    return await file.readAsString();  // Safe after validation
  }
}

// =============================================================================
// NULL SAFETY PATTERNS
// =============================================================================

class NullSafetyService {
  // UNSAFE: Null-aware operator with danger
  String processNullAwareUnsafe(String? input) {
    return input ?? 'default';  // Danger if not null
  }

  // UNSAFE: Null assertion
  String processNullAssertionUnsafe(String? input) {
    return input!;  // Danger (and potential crash)
  }

  // UNSAFE: Conditional access propagates danger
  String? processConditionalAccessUnsafe(String? input) {
    return input?.toUpperCase();  // Danger propagates
  }

  // UNSAFE: If-null assignment
  String processIfNullAssignmentUnsafe(String? input) {
    input ??= 'default';
    return input;  // May still be dangerous original value
  }

  // SAFE: Explicit constant
  String processNullSafe(String? input) {
    if (input == null) return 'default';
    return 'constant_value';  // Returns constant, not input
  }
}

// =============================================================================
// FUTURE/ASYNC-AWAIT PATTERNS
// =============================================================================

class AsyncService {
  // UNSAFE: Async propagates danger
  Future<String> processAsyncUnsafe(String input) async {
    final step1 = await _step1(input);  // Danger propagates
    final step2 = await _step2(step1);  // Still dangerous
    return step2;
  }

  Future<String> _step1(String value) async {
    return value.toUpperCase();
  }

  Future<String> _step2(String value) async {
    return 'processed: $value';
  }

  // UNSAFE: Future.then propagates danger
  Future<String> processThenUnsafe(String input) {
    return Future.value(input)
        .then((value) => value.toUpperCase())  // Danger propagates
        .then((value) => 'result: $value');
  }

  // SAFE: Async with constant
  Future<String> processAsyncSafe() async {
    final step1 = await _step1('constant');
    final step2 = await _step2(step1);
    return step2;
  }
}

// =============================================================================
// EXTENSION METHODS
// =============================================================================

extension StringProcessing on String {
  // UNSAFE: Extension on dangerous receiver
  String processUnsafe() {
    return this.toUpperCase();  // 'this' may be dangerous
  }

  // UNSAFE: Extension with dangerous parameter
  String appendUnsafe(String suffix) {
    return this + suffix;  // Both may be dangerous
  }
}

extension SafeProcessing on String {
  // SAFE: Extension with constant
  String appendSafe() {
    return this + '_suffix';  // Suffix is constant
  }
}

// =============================================================================
// VARIABLE PROPAGATION PATTERNS
// =============================================================================

class DataProcessor {
  // UNSAFE: Variable assignment propagates danger
  String processUnsafe(String input) {
    final processed = input;  // Assignment propagates
    final transformed = processed.toUpperCase();  // Method on dangerous
    return transformed;
  }

  // UNSAFE: Multiple assignments
  String chainAssignmentUnsafe(String value) {
    final a = value;
    final b = a;
    final c = b;
    return c;  // Danger propagates
  }

  // SAFE: Reassignment breaks danger
  String processSafe(String input) {
    var processed = input;
    processed = 'constant_value';  // Reassignment breaks danger
    return processed;
  }
}

// =============================================================================
// COLLECTION OPERATIONS
// =============================================================================

class CollectionService {
  // UNSAFE: Map propagates danger
  List<String> processMapUnsafe(List<String> inputs) {
    return inputs.map((e) => e.toUpperCase()).toList();  // Danger propagates
  }

  // UNSAFE: Where doesn't remove danger
  List<String> processWhereUnsafe(List<String> inputs) {
    return inputs.where((e) => e.isNotEmpty).toList();  // Still dangerous
  }

  // UNSAFE: Fold accumulates danger
  String processFoldUnsafe(List<String> inputs) {
    return inputs.fold('', (acc, e) => acc + e);  // Danger accumulates
  }

  // SAFE: Map to constants
  List<String> processMapSafe(List<String> inputs) {
    return inputs.map((e) => 'constant').toList();  // Transforms to constant
  }
}

// =============================================================================
// SHELF HTTP HANDLERS (Sources)
// =============================================================================

class ApiHandler {
  final UserRepository userRepository;
  final CommandService commandService;
  final FileService fileService;

  ApiHandler({
    required this.userRepository,
    required this.commandService,
    required this.fileService,
  });

  // UNSAFE: Query parameter to SQL
  Future<shelf.Response> handleUserUnsafe(shelf.Request request) async {
    final userId = request.url.queryParameters['id'] ?? '';  // Source
    final user = await userRepository.getUserUnsafeInterpolation(userId);  // Danger
    return shelf.Response.ok(user?.username ?? 'Not found');
  }

  // SAFE: Parameterized query
  Future<shelf.Response> handleUserSafe(shelf.Request request) async {
    final userId = request.url.queryParameters['id'] ?? '';  // Source
    final user = await userRepository.getUserSafeParameterized(userId);  // Safe
    return shelf.Response.ok(user?.username ?? 'Not found');
  }

  // UNSAFE: Path segment to command
  Future<shelf.Response> handleExecUnsafe(shelf.Request request, String filename) async {
    final result = await commandService.executeUnsafeShell(filename);  // Danger
    return shelf.Response.ok(result);
  }

  // UNSAFE: Query parameter to file read
  Future<shelf.Response> handleFileUnsafe(shelf.Request request) async {
    final filename = request.url.queryParameters['file'] ?? '';  // Source
    final content = await fileService.readFileUnsafeInterpolation(filename);  // Danger
    return shelf.Response.ok(content);
  }
}

// =============================================================================
// CONTROL FLOW PATTERNS
// =============================================================================

class ControlFlowService {
  // UNSAFE: Conditional with danger
  String conditionalUnsafe(String userInput) {
    if (userInput.isNotEmpty) {
      return userInput;  // Danger in true branch
    } else {
      return 'default';
    }
  }

  // UNSAFE: Ternary with danger
  String ternaryUnsafe(String userInput) {
    return userInput.isNotEmpty ? userInput : 'default';  // Danger
  }

  // UNSAFE: Switch with danger
  String switchUnsafe(String userInput, int code) {
    switch (code) {
      case 1:
        return userInput;  // Danger
      case 2:
        return 'option_b';
      default:
        return 'default';
    }
  }

  // SAFE: Both branches are constants
  String conditionalSafe(bool flag) {
    return flag ? 'option_a' : 'option_b';  // Both safe
  }
}
