//! {{project_name}}
//!
//! {{description}}

use wasm_bindgen::prelude::*;
use serde::{Deserialize, Serialize};

/// Main state for {{project_name}}
///
/// This uses a pure functional design - all state changes
/// return new State instances rather than mutating.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct State {
    pub counter: u32,
}

impl State {
    /// Create new state
    ///
    /// # Complexity
    /// - Time: O(1)
    /// - Cyclomatic: 1
    pub fn new() -> Self {
        Self { counter: 0 }
    }

    /// Increment counter (returns new state)
    ///
    /// # Complexity
    /// - Time: O(1)
    /// - Cyclomatic: 1
    pub fn increment(&self) -> Self {
        Self {
            counter: self.counter + 1,
        }
    }
}

impl Default for State {
    fn default() -> Self {
        Self::new()
    }
}

/// WASM entry point
///
/// # Complexity
/// - Time: O(1)
/// - Cyclomatic: 2
#[wasm_bindgen]
pub fn process(input: &str) -> Result<String, JsValue> {
    let state = State::new();
    let new_state = state.increment();

    serde_json::to_string(&new_state)
        .map(|s| format!("Processed '{}': {}", input, s))
        .map_err(|e| JsValue::from_str(&e.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_state_creation() {
        let state = State::new();
        assert_eq!(state.counter, 0);
    }

    #[test]
    fn test_state_increment() {
        let state = State::new();
        let new_state = state.increment();

        assert_eq!(new_state.counter, 1);
        assert_eq!(state.counter, 0); // Original unchanged
    }

    #[test]
    fn test_process() {
        let result = process("test").unwrap();
        assert!(result.contains("test"));
        assert!(result.contains("counter"));
    }
}

#[cfg(test)]
mod property_tests {
    use super::*;
    use proptest::prelude::*;

    proptest! {
        #[test]
        fn prop_increment_increases(count in 0u32..1000) {
            let state = State { counter: count };
            let new_state = state.increment();

            prop_assert_eq!(new_state.counter, count + 1);
        }

        #[test]
        fn prop_process_never_panics(input in ".*") {
            let _ = process(&input);
            // If we get here, no panic occurred
        }
    }
}
