import Foundation

/// Protocol for a calculation engine that evaluates text expressions.
/// The primary implementation is RustCalculationEngine (FFI bridge to calcpad-engine).
/// StubCalculationEngine is provided for testing without the Rust library.
protocol CalculationEngine: Sendable {
    /// Evaluate a single line expression and return the result string, or nil for blank/comment lines.
    func evaluateLine(_ line: String) -> LineResult

    /// Evaluate an entire sheet (multi-line text) and return results for each line.
    func evaluateSheet(_ text: String) -> [LineResult]
}

/// Stub engine for testing that handles basic arithmetic (+, -, *, /).
/// Used when the Rust engine library is not available.
final class StubCalculationEngine: CalculationEngine {

    func evaluateLine(_ line: String) -> LineResult {
        evaluateSingleLine(line, lineNumber: 1)
    }

    func evaluateSheet(_ text: String) -> [LineResult] {
        let lines = text.components(separatedBy: "\n")
        return lines.enumerated().map { index, line in
            evaluateSingleLine(line, lineNumber: index + 1)
        }
    }

    private func evaluateSingleLine(_ line: String, lineNumber: Int) -> LineResult {
        let trimmed = line.trimmingCharacters(in: .whitespaces)

        // Blank lines produce no result
        guard !trimmed.isEmpty else {
            return LineResult(id: lineNumber, expression: line, result: nil, isError: false)
        }

        // Comment lines (starting with // or #) produce no result
        if trimmed.hasPrefix("//") || trimmed.hasPrefix("#") {
            return LineResult(id: lineNumber, expression: line, result: nil, isError: false)
        }

        // Convert integer literals to floating-point so division produces decimals.
        // NSExpression does integer division for "7 / 2" -> 3, but we want 3.5.
        let floatExpr = trimmed.replacingOccurrences(
            of: #"\b(\d+)\b"#,
            with: "$1.0",
            options: .regularExpression
        )

        // Try to evaluate as a basic arithmetic expression
        do {
            let expr = NSExpression(format: floatExpr)
            if let value = expr.expressionValue(with: nil, context: nil) as? NSNumber {
                let doubleValue = value.doubleValue
                let formatted = String(format: "%g", doubleValue)
                return LineResult(id: lineNumber, expression: line, result: formatted, isError: false)
            }
        }

        return LineResult(id: lineNumber, expression: line, result: "Error", isError: true)
    }
}
