// 15_modules.ruchy - Module system and code organization

// Define a module
module math_utils {
    // Public function
    pub fn add(a, b) {
        a + b
    }

    pub fn multiply(a, b) {
        a * b
    }

    // Private function (not exported)
    fn internal_helper(x) {
        x * 2
    }

    pub fn complex_calc(x, y) {
        let temp = internal_helper(x)
        temp + multiply(y, 2)
    }

    // Nested module
    pub module geometry {
        pub fn area_circle(radius) {
            3.14159 * radius * radius
        }

        pub fn area_rectangle(width, height) {
            width * height
        }

        pub fn perimeter_rectangle(width, height) {
            2 * (width + height)
        }
    }

    // Constants
    pub const PI = 3.14159
    pub const E = 2.71828
}

// String utilities module
module string_utils {
    pub fn capitalize(s) {
        if s.len() == 0 {
            return s
        }
        let first = s[0].upper()
        let rest = s.slice(1)
        first + rest
    }

    pub fn reverse(s) {
        s.chars().reverse().join("")
    }

    pub fn is_palindrome(s) {
        let cleaned = s.lower().replace(" ", "")
        cleaned == reverse(cleaned)
    }

    pub fn word_count(text) {
        text.split(" ").filter(w => w.len() > 0).len()
    }
}

// Data structures module
module data_structures {
    pub struct Stack {
        items: list
    }

    impl Stack {
        pub fn new() {
            Stack { items: [] }
        }

        pub fn push(mut self, item) {
            self.items.append(item)
        }

        pub fn pop(mut self) {
            if self.items.len() > 0 {
                Some(self.items.remove_last())
            } else {
                None
            }
        }

        pub fn peek(self) {
            if self.items.len() > 0 {
                Some(self.items[self.items.len() - 1])
            } else {
                None
            }
        }

        pub fn is_empty(self) {
            self.items.len() == 0
        }
    }

    pub struct Queue {
        items: list
    }

    impl Queue {
        pub fn new() {
            Queue { items: [] }
        }

        pub fn enqueue(mut self, item) {
            self.items.append(item)
        }

        pub fn dequeue(mut self) {
            if self.items.len() > 0 {
                Some(self.items.remove(0))
            } else {
                None
            }
        }

        pub fn size(self) {
            self.items.len()
        }
    }
}

fn main() {
    println("=== Module System ===\n")

    // Using module functions
    println("=== Math Utils Module ===")

    let sum = math_utils::add(10, 20)
    println(f"10 + 20 = {sum}")

    let product = math_utils::multiply(5, 6)
    println(f"5 * 6 = {product}")

    let complex = math_utils::complex_calc(3, 4)
    println(f"Complex calculation: {complex}")

    // Using nested modules
    println("\n=== Geometry Submodule ===")

    let circle_area = math_utils::geometry::area_circle(5.0)
    println(f"Area of circle (r=5): {circle_area}")

    let rect_area = math_utils::geometry::area_rectangle(10.0, 20.0)
    println(f"Area of rectangle (10x20): {rect_area}")

    let perimeter = math_utils::geometry::perimeter_rectangle(10.0, 20.0)
    println(f"Perimeter of rectangle: {perimeter}")

    // Using constants
    println(f"PI constant: {math_utils::PI}")
    println(f"E constant: {math_utils::E}")

    // String utilities
    println("\n=== String Utils Module ===")

    let text = "hello world"
    let capitalized = string_utils::capitalize(text)
    println(f"Capitalized: {capitalized}")

    let reversed = string_utils::reverse(text)
    println(f"Reversed: {reversed}")

    let palindrome1 = "racecar"
    let palindrome2 = "hello"
    println(f"Is '{palindrome1}' a palindrome? {string_utils::is_palindrome(palindrome1)}")
    println(f"Is '{palindrome2}' a palindrome? {string_utils::is_palindrome(palindrome2)}")

    let sentence = "The quick brown fox jumps"
    let count = string_utils::word_count(sentence)
    println(f"Word count: {count}")

    // Data structures
    println("\n=== Data Structures Module ===")

    // Stack usage
    let mut stack = data_structures::Stack::new()
    stack.push(1)
    stack.push(2)
    stack.push(3)

    println("Stack operations:")
    match stack.pop() {
        Some(val) => println(f"  Popped: {val}"),
        None => println("  Stack is empty")
    }

    match stack.peek() {
        Some(val) => println(f"  Top element: {val}"),
        None => println("  Stack is empty")
    }

    // Queue usage
    let mut queue = data_structures::Queue::new()
    queue.enqueue("First")
    queue.enqueue("Second")
    queue.enqueue("Third")

    println("\nQueue operations:")
    println(f"  Queue size: {queue.size()}")

    match queue.dequeue() {
        Some(val) => println(f"  Dequeued: {val}"),
        None => println("  Queue is empty")
    }

    println(f"  Queue size after dequeue: {queue.size()}")

    // Using 'use' statements for convenience
    use math_utils::{add, multiply}
    use string_utils::reverse

    println("\n=== Using 'use' Statements ===")

    let result = add(5, 3)
    println(f"Direct call to add: {result}")

    let text_reversed = reverse("Ruchy")
    println(f"Direct call to reverse: {text_reversed}")

    // Wildcard imports
    use math_utils::geometry::*

    let area = area_circle(10.0)
    println(f"Circle area with wildcard import: {area}")

    // Module aliasing
    use math_utils as math
    use string_utils as str_util

    println("\n=== Module Aliases ===")

    let calc = math::add(100, 200)
    println(f"Using alias 'math': {calc}")

    let cap = str_util::capitalize("ruchy language")
    println(f"Using alias 'str_util': {cap}")
}