// 13_iterators.ruchy - Working with iterators and functional programming

fn main() {
    println("=== Iterators ===\n")

    // Basic iteration
    println("=== Basic Iteration ===")

    let numbers = [1, 2, 3, 4, 5]

    // Simple for loop
    for n in numbers {
        println(f"Number: {n}")
    }

    // Map operation
    println("\n=== Map ===")

    let doubled = numbers.map(x => x * 2)
    println(f"Original: {numbers}")
    println(f"Doubled: {doubled}")

    // Filter operation
    println("\n=== Filter ===")

    let evens = numbers.filter(x => x % 2 == 0)
    println(f"Even numbers: {evens}")

    // Reduce/Fold
    println("\n=== Reduce ===")

    let sum = numbers.reduce(0, (acc, x) => acc + x)
    println(f"Sum: {sum}")

    let product = numbers.reduce(1, (acc, x) => acc * x)
    println(f"Product: {product}")

    // Find operations
    println("\n=== Find Operations ===")

    let first_even = numbers.find(x => x % 2 == 0)
    match first_even {
        Some(n) => println(f"First even: {n}"),
        None => println("No even numbers")
    }

    let has_negative = numbers.any(x => x < 0)
    println(f"Has negative: {has_negative}")

    let all_positive = numbers.all(x => x > 0)
    println(f"All positive: {all_positive}")

    // Take and skip
    println("\n=== Take and Skip ===")

    let first_three = numbers.take(3)
    println(f"First 3: {first_three}")

    let skip_two = numbers.skip(2)
    println(f"After skipping 2: {skip_two}")

    // Zip
    println("\n=== Zip ===")

    let letters = ["a", "b", "c", "d", "e"]
    let pairs = numbers.zip(letters)
    println(f"Zipped pairs: {pairs}")

    // Enumerate
    println("\n=== Enumerate ===")

    for (index, value) in numbers.enumerate() {
        println(f"Index {index}: {value}")
    }

    // FlatMap
    println("\n=== FlatMap ===")

    let nested = [[1, 2], [3, 4], [5, 6]]
    let flattened = nested.flat_map(x => x)
    println(f"Flattened: {flattened}")

    let expanded = [1, 2, 3].flat_map(x => [x, x * 10])
    println(f"Expanded: {expanded}")

    // Partition
    println("\n=== Partition ===")

    let (evens, odds) = numbers.partition(x => x % 2 == 0)
    println(f"Evens: {evens}, Odds: {odds}")

    // Group by
    println("\n=== Group By ===")

    let words = ["apple", "ant", "banana", "bear", "cat", "car"]
    let grouped = words.group_by(w => w[0])
    println(f"Grouped by first letter: {grouped}")

    // Chain
    println("\n=== Chain ===")

    let first = [1, 2, 3]
    let second = [4, 5, 6]
    let chained = first.chain(second)
    println(f"Chained: {chained}")

    // Cycle
    println("\n=== Cycle ===")

    let pattern = [1, 2, 3]
    let cycled = pattern.cycle().take(10)
    println(f"Cycled pattern: {cycled}")

    // Scan (like reduce but returns intermediate values)
    println("\n=== Scan ===")

    let running_sum = numbers.scan(0, (acc, x) => acc + x)
    println(f"Running sum: {running_sum}")

    // Window
    println("\n=== Window ===")

    let windowed = numbers.windows(3)
    println("Windows of 3:")
    for window in windowed {
        println(f"  {window}")
    }

    // Chunks
    println("\n=== Chunks ===")

    let long_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    let chunks = long_list.chunks(3)
    println("Chunks of 3:")
    for chunk in chunks {
        println(f"  {chunk}")
    }

    // Custom iterator
    println("\n=== Custom Iterator ===")

    fn fibonacci(n) {
        let mut result = []
        let mut a = 0
        let mut b = 1

        for _ in 0..n {
            result.append(a)
            let temp = a + b
            a = b
            b = temp
        }
        result
    }

    let fib = fibonacci(10)
    println(f"Fibonacci: {fib}")

    // Iterator combinators
    println("\n=== Complex Combinations ===")

    let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    let result = data
        .filter(x => x % 2 == 0)        // Keep even
        .map(x => x * x)                 // Square them
        .filter(x => x < 50)             // Keep under 50
        .reduce(0, (a, b) => a + b)      // Sum them

    println(f"Complex result: {result}")

    // Lazy evaluation example
    println("\n=== Lazy Evaluation ===")

    let lazy_range = (0..1000000)
        .filter(x => x % 2 == 0)
        .map(x => x * 2)
        .take(5)

    println(f"First 5 from lazy evaluation: {lazy_range}")

    // Collect to different types
    println("\n=== Collect ===")

    let set = [1, 2, 2, 3, 3, 3].to_set()
    println(f"As set: {set}")

    let map = [(1, "one"), (2, "two"), (3, "three")].to_map()
    println(f"As map: {map}")
}