/**
 * Symbolic Evaluation Test File - JavaScript
 *
 * This file contains multiple source→sink flows for testing symbolic evaluation.
 * Each section demonstrates dangerous (unsafe) and safe patterns.
 *
 * Patterns covered:
 * - SQL injection (string concatenation vs parameterized queries)
 * - Command injection (child_process with user input)
 * - XSS (innerHTML with user input)
 * - Assignment and variable propagation
 * - Method invocation chains
 * - Binary operations (string concatenation, template literals)
 * - Control flow (conditionals, loops)
 */

const express = require("express");
const { exec, execSync, spawn } = require("child_process");
const mysql = require("mysql");
const fs = require("fs");

const app = express();
app.use(express.json());

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

class DatabaseService {
  constructor(connection) {
    this.connection = connection;
  }

  // UNSAFE: String concatenation with user input
  getUserUnsafeConcat(userId) {
    const query = "SELECT * FROM users WHERE id = '" + userId + "'";
    return this.connection.query(query); // Sink: danger propagates
  }

  // UNSAFE: Template literal with user input
  getUserUnsafeTemplate(username) {
    const query = `SELECT * FROM users WHERE username = '${username}'`;
    return this.connection.query(query); // Sink: danger propagates
  }

  // SAFE: Parameterized query
  getUserSafeParameterized(userId) {
    const query = "SELECT * FROM users WHERE id = ?";
    return this.connection.query(query, [userId]); // Safe: parameterized
  }

  // SAFE: Constant query
  getAllUsersSafe() {
    const query = "SELECT * FROM users";
    return this.connection.query(query); // Safe: constant
  }
}

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

class CommandService {
  // UNSAFE: exec with user input
  runCommandUnsafeExec(filename) {
    const command = "cat " + filename;
    return exec(command); // Sink: danger
  }

  // UNSAFE: execSync with template literal
  runCommandUnsafeSync(path) {
    const command = `ls ${path}`;
    return execSync(command); // Sink: danger
  }

  // SAFE: spawn with array arguments
  runCommandSafeSpawn(filename) {
    return spawn("cat", [filename]); // Safer: no shell interpretation
  }

  // SAFE: Constant command
  listDirectorySafe() {
    return exec("ls -la"); // Safe: constant
  }
}

// =============================================================================
// XSS / DOM MANIPULATION PATTERNS
// =============================================================================

class DomService {
  // UNSAFE: innerHTML with user input
  renderUnsafeInnerHTML(element, userContent) {
    element.innerHTML = userContent; // Sink: XSS danger
  }

  // UNSAFE: Template literal in innerHTML
  renderUnsafeTemplate(element, username) {
    element.innerHTML = `<span>Welcome, ${username}</span>`; // Sink: danger
  }

  // SAFE: textContent (escapes HTML)
  renderSafeTextContent(element, userContent) {
    element.textContent = userContent; // Safe: escaped
  }

  // SAFE: Constant content
  renderSafeConstant(element) {
    element.innerHTML = "<span>Welcome</span>"; // Safe: constant
  }
}

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

class FileService {
  constructor(basePath) {
    this.basePath = basePath;
  }

  // UNSAFE: Path concatenation
  readFileUnsafe(filename) {
    const path = this.basePath + "/" + filename;
    return fs.readFileSync(path); // Sink: path traversal danger
  }

  // UNSAFE: Template literal path
  readFileUnsafeTemplate(filename) {
    const path = `${this.basePath}/${filename}`;
    return fs.readFileSync(path); // Sink: danger
  }

  // SAFE: Validated path
  readFileSafe(filename) {
    if (filename.includes("..") || filename.startsWith("/")) {
      throw new Error("Invalid filename");
    }
    const path = `${this.basePath}/${filename}`;
    return fs.readFileSync(path); // Safe after validation
  }
}

// =============================================================================
// ASSIGNMENT AND VARIABLE PROPAGATION
// =============================================================================

class DataProcessor {
  // UNSAFE: Variable assignment propagates danger
  processInputUnsafe(data) {
    const processed = data; // Assignment propagates danger
    const transformed = processed.toUpperCase(); // Method on dangerous data
    return transformed;
  }

  // UNSAFE: Multiple assignments
  chainAssignmentUnsafe(value) {
    let a = value;
    let b = a;
    let c = b;
    return c; // Danger propagates through chain
  }

  // UNSAFE: Destructuring
  destructureUnsafe(obj) {
    const { userInput } = obj;
    return userInput; // Danger from destructured property
  }

  // SAFE: Reassignment to constant
  processInputSafe(data) {
    let processed = data;
    processed = "constant_value"; // Reassignment breaks danger
    return processed;
  }
}

// =============================================================================
// METHOD INVOCATION CHAINS
// =============================================================================

class ApiService {
  async fetch(url) {
    const response = await fetch(url);
    return response.json();
  }

  parse(data) {
    return data.result || "";
  }

  // UNSAFE: Chained calls with dangerous input
  async getDataUnsafe(endpoint) {
    const response = await this.fetch(endpoint); // Method with danger
    const data = this.parse(response);
    return data;
  }

  // SAFE: Constant endpoint
  async getDataSafe() {
    const response = await this.fetch("https://api.example.com/safe");
    const data = this.parse(response);
    return data;
  }
}

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

class ControlFlowService {
  // UNSAFE: Danger flows through conditional
  conditionalUnsafe(userInput) {
    let result;
    if (userInput.length > 0) {
      result = userInput; // Danger in true branch
    } else {
      result = "default";
    }
    return result; // Result may be dangerous
  }

  // UNSAFE: Danger in loop
  loopUnsafe(items) {
    let result = "";
    for (const item of items) {
      result = result + item; // Danger accumulates
    }
    return result;
  }

  // UNSAFE: Ternary with danger
  ternaryUnsafe(flag, userInput) {
    return flag ? userInput : "default"; // Danger in true case
  }

  // SAFE: All branches are safe
  conditionalSafe(flag) {
    return flag ? "option_a" : "option_b"; // Both are constants
  }
}

// =============================================================================
// EXPRESS REQUEST HANDLERS (Sources)
// =============================================================================

// UNSAFE: Direct use of query parameter in SQL
app.get("/search/unsafe", (req, res) => {
  const query = req.query.q; // Source: user input
  const db = new DatabaseService(mysql.createConnection({}));
  const result = db.getUserUnsafeConcat(query);
  res.json(result);
});

// SAFE: Parameterized query with request parameter
app.get("/search/safe", (req, res) => {
  const query = req.query.q; // Source: user input
  const db = new DatabaseService(mysql.createConnection({}));
  const result = db.getUserSafeParameterized(query); // Safe sink
  res.json(result);
});

// UNSAFE: Command injection via body
app.post("/exec/unsafe", (req, res) => {
  const filename = req.body.filename; // Source: user input
  const service = new CommandService();
  const result = service.runCommandUnsafeExec(filename);
  res.send(result);
});

// UNSAFE: Path traversal via params
app.get("/file/unsafe/:filename", (req, res) => {
  const filename = req.params.filename; // Source: user input
  const service = new FileService("/var/data");
  const content = service.readFileUnsafe(filename);
  res.send(content);
});

// SAFE: Validated file read
app.get("/file/safe/:filename", (req, res) => {
  const filename = req.params.filename; // Source: user input
  const service = new FileService("/var/data");
  const content = service.readFileSafe(filename); // Safe after validation
  res.send(content);
});

module.exports = { app, DatabaseService, CommandService, FileService };
