# Core Types Foundation Library

Pure type definitions for Rustelo's configuration-driven web application framework. This crate provides the essential data structures that represent your TOML configuration as strongly-typed Rust structs.

> **🎯 Zero Build Dependencies**: This crate intentionally has minimal dependencies to avoid circular dependency issues while providing the type foundation for build-time code generation.

## Quick Start

### Pattern 1: Using Generated Types (Recommended)

The core-types are primarily used internally by the build system, but you can access them when you need to work with configuration data:

```rust
use core_types::{
    RouteConfigToml, RoutesConfig, BasicContentItem, 
    ContentKindRegistry, MenuConfig, ThemeConfig
};

// Your TOML configuration becomes strongly-typed structs
fn process_route_configuration(config: RoutesConfig) {
    for route in config.routes {
        println!("Route: {} -> {}", route.path, route.component);
        println!("  Title key: {}", route.title_key);
        println!("  Language: {}", route.language);
        
        if let Some(content_type) = route.content_type {
            println!("  Content type: {}", content_type);
        }
    }
}

// Content items from your markdown files become typed structs
fn process_content_item(item: BasicContentItem) {
    println!("Content: {} ({})", item.title, item.content_type);
    println!("  Language: {}", item.language);
    println!("  Published: {}", item.published);
    println!("  Slug: {}", item.slug);
}
```

### Pattern 2: Configuration Validation

Use core-types for validating TOML configuration during build:

```rust
use core_types::{RouteConfigToml, ContentConfig, MenuConfig};
use std::collections::HashMap;

// Validate route configuration from TOML
fn validate_route_config(toml_content: &str) -> Result<RoutesConfig, String> {
    // Parse TOML into strongly-typed structs
    let routes_config: RoutesConfig = toml::from_str(toml_content)
        .map_err(|e| format!("Invalid route configuration: {}", e))?;
    
    // Validate required fields
    for route in &routes_config.routes {
        if route.path.is_empty() {
            return Err(format!("Route missing path: {:?}", route));
        }
        
        if route.component.is_empty() {
            return Err(format!("Route missing component: {}", route.path));
        }
        
        if route.title_key.is_empty() {
            return Err(format!("Route missing title_key: {}", route.path));
        }
        
        // Validate path format
        if !route.path.starts_with('/') {
            return Err(format!("Route path must start with '/': {}", route.path));
        }
    }
    
    Ok(routes_config)
}

// Validate content-kinds.toml configuration
fn validate_content_kinds(toml_content: &str) -> Result<HashMap<String, ContentConfig>, String> {
    let content_kinds: HashMap<String, ContentConfig> = toml::from_str(toml_content)
        .map_err(|e| format!("Invalid content kinds configuration: {}", e))?;
    
    for (name, config) in &content_kinds {
        if config.title.is_empty() {
            return Err(format!("Content kind '{}' missing title", name));
        }
        
        if config.directory.is_empty() {
            return Err(format!("Content kind '{}' missing directory", name));
        }
    }
    
    Ok(content_kinds)
}
```

## Configuration-Driven Type System

Core-types provides the foundation for Rustelo's configuration-driven architecture by defining how TOML configuration maps to Rust types:

### Route Configuration Types

**TOML Configuration:**
```toml
# site/config/routes/en.toml
[[routes]]
path = "/about"
component = "About"
title_key = "about-title"
description_key = "about-description"
language = "en"
enabled = true
menu_group = "main"
menu_order = 2
```

**Generated Rust Types:**
```rust
use core_types::RouteConfigToml;

// Your TOML automatically becomes this typed struct
let route = RouteConfigToml {
    path: "/about".to_string(),
    component: "About".to_string(),
    title_key: "about-title".to_string(),
    description_key: Some("about-description".to_string()),
    language: "en".to_string(),
    enabled: true,
    menu_group: Some("main".to_string()),
    menu_order: Some(2),
    // ... other fields with proper defaults
};
```

### Content Type Configuration

**TOML Configuration:**
```toml
# content/content-kinds.toml
[blog]
title = "Blog Posts"
directory = "blog"
enabled = true
icon = "📝"
color = "#3B82F6"
features = ["categories", "tags", "comments"]
```

**Generated Rust Types:**
```rust
use core_types::{ContentConfig, ContentFeatures};

// Your content configuration becomes typed structs
let blog_config = ContentConfig {
    name: "blog".to_string(),
    title: "Blog Posts".to_string(), 
    directory: "blog".to_string(),
    enabled: true,
    icon: Some("📝".to_string()),
    color: Some("#3B82F6".to_string()),
    features: ContentFeatures {
        categories: true,
        tags: true,
        comments: true,
        ..Default::default()
    },
    // ... other fields
};
```

### Content Item Types

```rust
use core_types::{BasicContentItem, Metadata};

// Markdown files become typed content items
let blog_post = BasicContentItem {
    id: "unique-post-id".to_string(),
    title: "My First Post".to_string(),
    slug: "my-first-post".to_string(),
    content_type: "blog".to_string(),
    language: "en".to_string(),
    published: true,
    content: Some("# Hello World\nThis is my first post!".to_string()),
    html_content: Some("<h1>Hello World</h1><p>This is my first post!</p>".to_string()),
    metadata: Metadata {
        description: Some("My first blog post".to_string()),
        keywords: vec!["blog".to_string(), "first".to_string()],
        author: Some("Author Name".to_string()),
        // ... other metadata
        ..Default::default()
    },
    // ... timestamps and other fields
    ..Default::default()
};
```

## Available Types

### Core Configuration Types

#### `RouteConfigToml`
Represents a single route from your TOML configuration:
```rust
pub struct RouteConfigToml {
    pub path: String,              // "/about"
    pub component: String,         // "About" 
    pub language: String,          // "en"
    pub title_key: String,         // "about-title"
    pub description_key: Option<String>,
    pub enabled: bool,
    pub priority: Option<f32>,
    pub keywords: Option<Vec<String>>,
    pub menu_group: Option<String>,
    pub menu_order: Option<i32>,
    // ... and many more fields
}
```

#### `RoutesConfig`
Container for multiple routes:
```rust
pub struct RoutesConfig {
    pub routes: Vec<RouteConfigToml>,
    pub settings: Option<HashMap<String, String>>,
}
```

### Content System Types

#### `BasicContentItem`
Represents content loaded from markdown files:
```rust
pub struct BasicContentItem {
    pub id: String,
    pub title: String,
    pub slug: String,
    pub content_type: String,      // "blog", "page", etc.
    pub language: String,          // "en", "es", etc.
    pub metadata: Metadata,
    pub content: Option<String>,   // Raw markdown
    pub html_content: Option<String>, // Rendered HTML
    pub published: bool,
    // ... timestamps and other fields
}
```

#### `ContentConfig`
Configuration for content types from content-kinds.toml:
```rust
pub struct ContentConfig {
    pub name: String,              // "blog"
    pub title: String,             // "Blog Posts"
    pub directory: String,         // "blog"
    pub enabled: bool,
    pub is_default: Option<bool>,
    pub specialized: Option<Vec<String>>,
    pub features: ContentFeatures,
    // ... other configuration
}
```

#### `ContentFeatures`
Feature flags for content types:
```rust  
pub struct ContentFeatures {
    pub categories: bool,
    pub tags: bool,
    pub comments: bool,
    pub search: bool,
    pub archive: bool,
    // ... other features
}
```

### UI Configuration Types

#### `MenuConfig`
Menu configuration from menu.toml:
```rust
pub struct MenuConfig {
    pub menu: Vec<MenuItem>,
}

pub struct MenuItem {
    pub title: String,
    pub url: String,
    pub icon: Option<String>,
    pub target: NavigationTarget,
    pub children: Vec<MenuItem>,
}
```

#### `ThemeConfig`
Theme configuration:
```rust
pub struct ThemeConfig {
    pub primary_color: String,
    pub secondary_color: String,
    pub background_color: String,
    pub text_color: String,
    // ... other theme properties
}
```

#### `DesignSystemConfig`
Complete design system configuration:
```rust
pub struct DesignSystemConfig {
    pub theme: ColorConfig,
    pub typography: TypographyConfig,
    pub spacing: SpacingConfig,
    pub breakpoints: BreakpointConfig,
}
```

## Type Validation and Safety

Core-types provides validation methods for configuration data:

```rust
use core_types::{RouteConfigToml, ContentConfig};

impl RouteConfigToml {
    /// Validate that this route configuration is valid
    pub fn validate(&self) -> Result<(), String> {
        if self.path.is_empty() {
            return Err("Path cannot be empty".to_string());
        }
        
        if !self.path.starts_with('/') {
            return Err("Path must start with '/'".to_string());
        }
        
        if self.component.is_empty() {
            return Err("Component cannot be empty".to_string());
        }
        
        if self.title_key.is_empty() {
            return Err("Title key cannot be empty".to_string());
        }
        
        Ok(())
    }
    
    /// Check if this route should be included in sitemaps
    pub fn include_in_sitemap(&self) -> bool {
        self.show_in_sitemap.unwrap_or(true) && self.enabled
    }
    
    /// Check if this route requires authentication
    pub fn requires_authentication(&self) -> bool {
        self.requires_auth.unwrap_or(false)
    }
}

impl ContentConfig {
    /// Validate content configuration
    pub fn validate(&self) -> Result<(), String> {
        if self.name.is_empty() {
            return Err("Name cannot be empty".to_string());
        }
        
        if self.title.is_empty() {
            return Err("Title cannot be empty".to_string());
        }
        
        if self.directory.is_empty() {
            return Err("Directory cannot be empty".to_string());
        }
        
        Ok(())
    }
    
    /// Check if this content type has a specific feature enabled
    pub fn has_feature(&self, feature: &str) -> bool {
        match feature {
            "categories" => self.features.categories,
            "tags" => self.features.tags,
            "comments" => self.features.comments,
            "search" => self.features.search,
            _ => false,
        }
    }
}
```

## Serialization and Deserialization

All types implement `Serialize` and `Deserialize` for seamless TOML/JSON conversion:

```rust
use core_types::{RouteConfigToml, RoutesConfig};

// Load from TOML
fn load_routes_from_toml(toml_content: &str) -> Result<RoutesConfig, toml::de::Error> {
    toml::from_str(toml_content)
}

// Save to TOML  
fn save_routes_to_toml(config: &RoutesConfig) -> Result<String, toml::ser::Error> {
    toml::to_string_pretty(config)
}

// Load from JSON (for API integration)
fn load_routes_from_json(json_content: &str) -> Result<RoutesConfig, serde_json::Error> {
    serde_json::from_str(json_content)
}

// Convert between formats
fn convert_toml_to_json(toml_content: &str) -> Result<String, Box<dyn std::error::Error>> {
    let routes: RoutesConfig = toml::from_str(toml_content)?;
    let json = serde_json::to_string_pretty(&routes)?;
    Ok(json)
}
```

## Integration with Build System

Core-types serves as the bridge between your TOML configuration and the build-time code generation:

```rust
// In build.rs
use core_types::{RoutesConfig, RouteConfigToml};

fn generate_components_from_config(config: &RoutesConfig) -> Result<String, std::io::Error> {
    let mut generated_code = String::new();
    
    // Generate RouteComponent enum
    generated_code.push_str("#[derive(Debug, Clone, PartialEq, Eq)]\n");
    generated_code.push_str("pub enum RouteComponent {\n");
    
    for route in &config.routes {
        let component_name = &route.component;
        generated_code.push_str(&format!("    {},\n", component_name));
    }
    
    generated_code.push_str("}\n\n");
    
    // Generate page components
    for route in &config.routes {
        generated_code.push_str(&generate_component_from_route(route));
    }
    
    Ok(generated_code)
}

fn generate_component_from_route(route: &RouteConfigToml) -> String {
    format!(
        r#"
#[component]
pub fn {}Page() -> impl IntoView {{
    let title = t("{}");
    let description = t("{}");
    
    view! {{
        <div class="page-container {}-page">
            <PageHeader title=title description=description />
            <PageContent />
        </div>
    }}
}}
"#,
        route.component,
        route.title_key,
        route.description_key.as_deref().unwrap_or("default-description"),
        route.component.to_lowercase()
    )
}
```

## Testing and Validation

```rust
#[cfg(test)]
mod tests {
    use super::*;
    use core_types::{RouteConfigToml, ContentConfig, BasicContentItem};
    
    #[test]
    fn test_route_validation() {
        let valid_route = RouteConfigToml {
            path: "/about".to_string(),
            component: "About".to_string(),
            title_key: "about-title".to_string(),
            language: "en".to_string(),
            enabled: true,
            ..Default::default()
        };
        
        assert!(valid_route.validate().is_ok());
        
        let invalid_route = RouteConfigToml {
            path: "about".to_string(), // Missing leading slash
            component: "".to_string(), // Empty component
            ..Default::default()
        };
        
        assert!(invalid_route.validate().is_err());
    }
    
    #[test]
    fn test_content_config_serialization() {
        let config = ContentConfig {
            name: "blog".to_string(),
            title: "Blog Posts".to_string(),
            directory: "blog".to_string(),
            enabled: true,
            ..Default::default()
        };
        
        // Test TOML serialization
        let toml_str = toml::to_string(&config).unwrap();
        let deserialized: ContentConfig = toml::from_str(&toml_str).unwrap();
        
        assert_eq!(config.name, deserialized.name);
        assert_eq!(config.title, deserialized.title);
    }
    
    #[test]
    fn test_content_item_defaults() {
        let item = BasicContentItem::default();
        
        assert_eq!(item.content_type, "page");
        assert_eq!(item.language, "en");
        assert!(item.published);
        assert!(item.id.is_empty());
    }
}
```

## API Reference

### Core Types
- **`RouteConfigToml`** - Single route configuration from TOML
- **`RoutesConfig`** - Collection of routes with settings
- **`BasicContentItem`** - Content item from markdown files
- **`ContentConfig`** - Content type configuration
- **`ContentKindRegistry`** - Registry of all content types
- **`MenuConfig`** - Navigation menu configuration
- **`ThemeConfig`** - Visual theme configuration
- **`DesignSystemConfig`** - Complete design system

### Utility Functions
- **Validation methods** - `validate()` on configuration types
- **Feature checking** - `has_feature()` for content configurations
- **Default implementations** - Sensible defaults for all types
- **Serialization support** - TOML/JSON conversion for all types

## Best Practices

1. **Use validation methods** - Always call `validate()` on configuration data
2. **Handle options properly** - Many fields are `Option<T>` for flexible configuration
3. **Leverage defaults** - Use `Default::default()` for base configurations
4. **Type-safe configuration** - Use these types instead of raw HashMap/JSON
5. **Build-time validation** - Validate configuration during build, not runtime

## Contributing

Core-types is designed to be stable and minimal:

1. **Add new types** - Only add types needed by multiple crates
2. **Maintain zero build dependencies** - Keep this crate dependency-light
3. **Document all fields** - Every field should have clear documentation
4. **Provide validation** - Add validation methods for complex types
5. **Test thoroughly** - All types should have comprehensive tests

## License

MIT License - See LICENSE file for details.
