{-# LANGUAGE OverloadedStrings #-}
-- | Module: Gram.Schema.Rust
--
-- Generates Rust type definitions for Pattern<Subject>.
--
-- This module provides functions to generate Rust structs and enums
-- that model Pattern<Subject> for downstream Rust ports.
--
-- @since 0.1.0
module Gram.Schema.Rust
  ( generateRustTypes
  ) where

import qualified Data.Text as T
import Data.Text (Text)

-- | Generate Rust type definitions for Pattern<Subject>
--
-- Returns Rust code with:
-- - Struct definitions for Pattern, Subject with serde derives
-- - Enum definition for Value types with #[serde(untagged)]
-- - Convenience constructors (new methods) for complex types
-- - Doc comments for documentation
--
-- Example usage:
-- @
-- let rustCode = generateRustTypes
-- writeFile "pattern.rs" (T.unpack rustCode)
-- @
--
-- @since 0.1.0
generateRustTypes :: Text
generateRustTypes :: Text
generateRustTypes = [Text] -> Text
T.unlines
  [ Text
"//! Pattern<Subject> Rust Type Definitions"
  , Text
"//! Generated from gram-hs canonical JSON Schema"
  , Text
"//! Version: 0.1.0"
  , Text
""
  , Text
"use serde::{Deserialize, Serialize};"
  , Text
"use std::collections::HashMap;"
  , Text
""
  , Text
"/// A pattern with a subject and optional nested pattern elements."
  , Text
"///"
  , Text
"/// Patterns are recursive: they can contain other patterns as elements."
  , Text
"#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
  , Text
"pub struct Pattern {"
  , Text
"    /// The subject of this pattern"
  , Text
"    pub subject: Subject,"
  , Text
"    /// Nested pattern elements"
  , Text
"    pub elements: Vec<Pattern>,"
  , Text
"}"
  , Text
""
  , Text
"impl Pattern {"
  , Text
"    /// Create a new Pattern with a subject and elements"
  , Text
"    pub fn new(subject: Subject, elements: Vec<Pattern>) -> Self {"
  , Text
"        Self { subject, elements }"
  , Text
"    }"
  , Text
""
  , Text
"    /// Create a new Pattern with a subject and no elements"
  , Text
"    pub fn leaf(subject: Subject) -> Self {"
  , Text
"        Self { subject, elements: Vec::new() }"
  , Text
"    }"
  , Text
"}"
  , Text
""
  , Text
"/// A subject with identity, labels, and properties."
  , Text
"#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
  , Text
"pub struct Subject {"
  , Text
"    /// Identity symbol for the subject"
  , Text
"    pub identity: String,"
  , Text
"    /// Set of labels classifying the subject"
  , Text
"    pub labels: Vec<String>,"
  , Text
"    /// Map of property names to values"
  , Text
"    pub properties: HashMap<String, Value>,"
  , Text
"}"
  , Text
""
  , Text
"impl Subject {"
  , Text
"    /// Create a new Subject with identity, labels, and properties"
  , Text
"    pub fn new(identity: String, labels: Vec<String>, properties: HashMap<String, Value>) -> Self {"
  , Text
"        Self { identity, labels, properties }"
  , Text
"    }"
  , Text
""
  , Text
"    /// Create a new Subject with just an identity (no labels or properties)"
  , Text
"    pub fn simple(identity: String) -> Self {"
  , Text
"        Self {"
  , Text
"            identity,"
  , Text
"            labels: Vec::new(),"
  , Text
"            properties: HashMap::new(),"
  , Text
"        }"
  , Text
"    }"
  , Text
"}"
  , Text
""
  , Text
"/// Symbol value with type discriminator"
  , Text
"#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
  , Text
"pub struct ValueSymbol {"
  , Text
"    #[serde(rename = \"type\")]"
  , Text
"    pub type_: String,"
  , Text
"    pub value: String,"
  , Text
"}"
  , Text
""
  , Text
"impl ValueSymbol {"
  , Text
"    /// Create a new ValueSymbol"
  , Text
"    pub fn new(value: String) -> Self {"
  , Text
"        Self {"
  , Text
"            type_: \"symbol\".to_string(),"
  , Text
"            value,"
  , Text
"        }"
  , Text
"    }"
  , Text
"}"
  , Text
""
  , Text
"/// Tagged string value (e.g., URL, JSON, code)"
  , Text
"#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
  , Text
"pub struct ValueTaggedString {"
  , Text
"    #[serde(rename = \"type\")]"
  , Text
"    pub type_: String,"
  , Text
"    pub tag: String,"
  , Text
"    pub content: String,"
  , Text
"}"
  , Text
""
  , Text
"impl ValueTaggedString {"
  , Text
"    /// Create a new ValueTaggedString"
  , Text
"    pub fn new(tag: String, content: String) -> Self {"
  , Text
"        Self {"
  , Text
"            type_: \"tagged\".to_string(),"
  , Text
"            tag,"
  , Text
"            content,"
  , Text
"        }"
  , Text
"    }"
  , Text
"}"
  , Text
""
  , Text
"/// Numeric range value with optional bounds"
  , Text
"#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
  , Text
"pub struct ValueRange {"
  , Text
"    #[serde(rename = \"type\")]"
  , Text
"    pub type_: String,"
  , Text
"    pub lower: Option<f64>,"
  , Text
"    pub upper: Option<f64>,"
  , Text
"}"
  , Text
""
  , Text
"impl ValueRange {"
  , Text
"    /// Create a new ValueRange with both bounds"
  , Text
"    pub fn new(lower: Option<f64>, upper: Option<f64>) -> Self {"
  , Text
"        Self {"
  , Text
"            type_: \"range\".to_string(),"
  , Text
"            lower,"
  , Text
"            upper,"
  , Text
"        }"
  , Text
"    }"
  , Text
""
  , Text
"    /// Create a closed range (both bounds present)"
  , Text
"    pub fn closed(lower: f64, upper: f64) -> Self {"
  , Text
"        Self::new(Some(lower), Some(upper))"
  , Text
"    }"
  , Text
"}"
  , Text
""
  , Text
"/// Measurement value with unit and numeric value"
  , Text
"#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
  , Text
"pub struct ValueMeasurement {"
  , Text
"    #[serde(rename = \"type\")]"
  , Text
"    pub type_: String,"
  , Text
"    pub unit: String,"
  , Text
"    pub value: f64,"
  , Text
"}"
  , Text
""
  , Text
"impl ValueMeasurement {"
  , Text
"    /// Create a new ValueMeasurement"
  , Text
"    pub fn new(unit: String, value: f64) -> Self {"
  , Text
"        Self {"
  , Text
"            type_: \"measurement\".to_string(),"
  , Text
"            unit,"
  , Text
"            value,"
  , Text
"        }"
  , Text
"    }"
  , Text
"}"
  , Text
""
  , Text
"/// Value can be integer, number, boolean, string, symbol, tagged string,"
  , Text
"/// array, map, range, or measurement."
  , Text
"///"
  , Text
"/// This uses serde's untagged enum for flexible JSON deserialization."
  , Text
"/// Complex types use a 'type' field for discrimination."
  , Text
"#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
  , Text
"#[serde(untagged)]"
  , Text
"pub enum Value {"
  , Text
"    /// Symbol value"
  , Text
"    Symbol(ValueSymbol),"
  , Text
"    /// Tagged string value"
  , Text
"    TaggedString(ValueTaggedString),"
  , Text
"    /// Range value"
  , Text
"    Range(ValueRange),"
  , Text
"    /// Measurement value"
  , Text
"    Measurement(ValueMeasurement),"
  , Text
"    /// Array of values"
  , Text
"    Array(Vec<Value>),"
  , Text
"    /// Map of string keys to values (plain object without 'type' field)"
  , Text
"    Map(HashMap<String, Value>),"
  , Text
"    /// Integer or floating-point number"
  , Text
"    Number(f64),"
  , Text
"    /// Boolean value"
  , Text
"    Boolean(bool),"
  , Text
"    /// String value"
  , Text
"    String(String),"
  , Text
"}"
  , Text
""
  , Text
"impl Value {"
  , Text
"    /// Check if this value is a symbol"
  , Text
"    pub fn is_symbol(&self) -> bool {"
  , Text
"        matches!(self, Value::Symbol(_))"
  , Text
"    }"
  , Text
""
  , Text
"    /// Check if this value is a tagged string"
  , Text
"    pub fn is_tagged_string(&self) -> bool {"
  , Text
"        matches!(self, Value::TaggedString(_))"
  , Text
"    }"
  , Text
""
  , Text
"    /// Check if this value is a range"
  , Text
"    pub fn is_range(&self) -> bool {"
  , Text
"        matches!(self, Value::Range(_))"
  , Text
"    }"
  , Text
""
  , Text
"    /// Check if this value is a measurement"
  , Text
"    pub fn is_measurement(&self) -> bool {"
  , Text
"        matches!(self, Value::Measurement(_))"
  , Text
"    }"
  , Text
""
  , Text
"    /// Check if this value is an array"
  , Text
"    pub fn is_array(&self) -> bool {"
  , Text
"        matches!(self, Value::Array(_))"
  , Text
"    }"
  , Text
""
  , Text
"    /// Check if this value is a map"
  , Text
"    pub fn is_map(&self) -> bool {"
  , Text
"        matches!(self, Value::Map(_))"
  , Text
"    }"
  , Text
"}"
  ]