---
# Generated Traits Template - REGENERATE FREELY
#
# This template generates:
# - Trait definitions for each noun (UserCommands, OrderCommands, etc.)
# - Output types from RDF schema
# - CLI routing with clap macros
#
# SAFE TO REGENERATE: Domain logic lives in src/domain/ and is NOT touched.
#
# Usage:
#   ggen generate \
#     --template clap-noun-verb/templates/generated-traits.tmpl \
#     --domain ontology/cli.ttl \
#     --output src/generated/ \
#     --force

to: "."
rdf: "{{ domain_rdf }}"
prefixes:
  cnv: "https://ggen.dev/clap-noun-verb/"
  rdfs: "http://www.w3.org/2000/01/rdf-schema#"
  rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#"

sparql:
  project: |
    SELECT ?name ?version ?description WHERE {
      ?proj a cnv:CliProject ;
            cnv:projectName ?name .
      OPTIONAL { ?proj cnv:projectVersion ?version }
      OPTIONAL { ?proj rdfs:comment ?description }
    }
    LIMIT 1

  nouns: |
    SELECT ?noun ?name ?description WHERE {
      ?noun a cnv:Noun ;
            cnv:nounName ?name .
      OPTIONAL { ?noun rdfs:comment ?description }
    }
    ORDER BY ?name

  verbs: |
    SELECT ?verb ?name ?noun_name ?description WHERE {
      ?noun a cnv:Noun ;
            cnv:nounName ?noun_name ;
            cnv:hasVerbs ?verb .
      ?verb a cnv:Verb ;
            cnv:verbName ?name .
      OPTIONAL { ?verb rdfs:comment ?description }
    }
    ORDER BY ?noun_name ?name

  arguments: |
    SELECT ?arg ?name ?rust_type ?verb_name ?required ?help WHERE {
      ?verb a cnv:Verb ;
            cnv:verbName ?verb_name ;
            cnv:hasArguments ?arg .
      ?arg a cnv:Argument ;
           cnv:argumentName ?name ;
           cnv:argumentType ?type_node .
      ?type_node cnv:rust-type ?rust_type .
      OPTIONAL { ?arg cnv:required ?required }
      OPTIONAL { ?arg rdfs:comment ?help }
    }
    ORDER BY ?verb_name ?name

  output_types: |
    SELECT ?type ?name ?rust_type WHERE {
      ?type a cnv:OutputType ;
            cnv:typeName ?name ;
            cnv:rust-type ?rust_type .
    }
    ORDER BY ?name
---
{# FILE: mod.rs #}
// ⚠️ DO NOT EDIT - Generated by ggen from {{ domain_rdf }}
// Regenerate with: ggen generate --domain {{ domain_rdf }} --output src/generated/ --force
//
// Your changes WILL BE LOST on next regeneration.
// Implement business logic in src/domain/ instead.

//! Generated CLI Traits and Types
//!
//! This module contains:
//! - Trait definitions for each noun (implement in src/domain/)
//! - Output types generated from RDF schema
//! - CLI routing (clap macros)
//!
//! Architecture:
//! ```text
//! src/generated/     ← YOU ARE HERE (regenerate freely)
//! ├── mod.rs         ← This file
//! └── nouns/
//!     ├── user.rs    ← trait UserCommands
//!     └── order.rs   ← trait OrderCommands
//!
//! src/domain/        ← YOUR CODE (never touched by generator)
//! ├── user.rs        ← impl UserCommands for UserDomain
//! └── order.rs       ← impl OrderCommands for OrderDomain
//! ```

pub mod nouns;
pub mod routing;
pub mod types;

// Re-export all traits for easy importing
{% for noun in sparql_results.nouns %}
pub use nouns::{{ noun.name | trim_matches(pat='"') }}::{{ noun.name | trim_matches(pat='"') | title }}Commands;
{% endfor %}

{# FILE: types.rs #}
// ⚠️ DO NOT EDIT - Generated by ggen from {{ domain_rdf }}

//! Generated Output Types
//!
//! These types are generated from RDF schema and define the contract
//! between CLI and domain layers.

use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};

{% for output_type in sparql_results.output_types %}
/// Output type: {{ output_type.name | trim_matches(pat='"') }}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct {{ output_type.name | trim_matches(pat='"') }} {
    // TODO: Fields generated from RDF schema
    pub id: String,
}

{% endfor %}

// Common output types for CRUD operations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreatedOutput<T> {
    pub id: String,
    pub data: T,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeletedOutput {
    pub id: String,
    pub deleted_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListOutput<T> {
    pub items: Vec<T>,
    pub total: usize,
    pub page: usize,
    pub page_size: usize,
}

{# FILE: routing.rs #}
// ⚠️ DO NOT EDIT - Generated by ggen from {{ domain_rdf }}

//! CLI Routing - Clap command tree
//!
//! This module wires CLI arguments to domain trait methods.
//! The actual business logic is in src/domain/.

use clap_noun_verb::Result;
use clap_noun_verb_macros::noun;
use serde_json;

use crate::domain;
use crate::error::CliError;

{% for noun in sparql_results.nouns %}
// ============================================================================
// {{ noun.name | trim_matches(pat='"') | upper }} Commands
// ============================================================================

#[noun("{{ noun.name | trim_matches(pat='"') }}", "{{ noun.description | default(value=noun.name) | trim_matches(pat='"') }}")]
pub mod {{ noun.name | trim_matches(pat='"') }}_commands {
    use super::*;
    use clap_noun_verb_macros::verb;

{% for verb in sparql_results.verbs %}{% if verb.noun_name | trim_matches(pat='"') == noun.name | trim_matches(pat='"') %}
    /// {{ verb.description | default(value=verb.name) | trim_matches(pat='"') }}
    #[verb("{{ verb.name | trim_matches(pat='"') }}")]
    pub fn {{ verb.name | trim_matches(pat='"') }}(
{% for arg in sparql_results.arguments %}{% if arg.verb_name | trim_matches(pat='"') == verb.name | trim_matches(pat='"') %}
        #[arg(help = "{{ arg.help | default(value=arg.name) | trim_matches(pat='"') }}")] {{ arg.name | trim_matches(pat='"') }}: {{ arg.rust_type | trim_matches(pat='"') }},
{% endif %}{% endfor %}
    ) -> Result<serde_json::Value> {
        // Telemetry hook (generated when telemetry_enabled=true)
        #[cfg(feature = "telemetry")]
        let _span = tracing::info_span!(
            "{{ noun.name | trim_matches(pat='"') }}.{{ verb.name | trim_matches(pat='"') }}",
        ).entered();

        // Feature flag hook (generated when feature_flags_enabled=true)
        #[cfg(feature = "feature-flags")]
        {
            if !crate::infrastructure::feature_flags::is_enabled("{{ noun.name | trim_matches(pat='"') }}.{{ verb.name | trim_matches(pat='"') }}") {
                return Err(CliError::FeatureDisabled("{{ noun.name | trim_matches(pat='"') }}.{{ verb.name | trim_matches(pat='"') }}".into()).into());
            }
        }

        // Delegate to domain layer
        let result = domain::{{ noun.name | trim_matches(pat='"') }}::{{ verb.name | trim_matches(pat='"') }}(
{% for arg in sparql_results.arguments %}{% if arg.verb_name | trim_matches(pat='"') == verb.name | trim_matches(pat='"') %}
            {{ arg.name | trim_matches(pat='"') }},
{% endif %}{% endfor %}
        ).map_err(CliError::from)?;

        Ok(serde_json::to_value(&result).map_err(|e| CliError::Serialization(e.to_string()))?)
    }

{% endif %}{% endfor %}
}

{% endfor %}

{# FILE: nouns/mod.rs #}
// ⚠️ DO NOT EDIT - Generated by ggen from {{ domain_rdf }}

//! Noun Trait Modules
//!
//! Each noun has a trait defining its commands. Implement these traits
//! in src/domain/ to provide business logic.

{% for noun in sparql_results.nouns %}
pub mod {{ noun.name | trim_matches(pat='"') }};
{% endfor %}

{% for noun in sparql_results.nouns %}
{# FILE: nouns/{{ noun.name | trim_matches(pat='"') }}.rs #}
// ⚠️ DO NOT EDIT - Generated by ggen from {{ domain_rdf }}

//! {{ noun.name | trim_matches(pat='"') | title }} Noun - Trait Definition
//!
//! Implement this trait in `src/domain/{{ noun.name | trim_matches(pat='"') }}.rs`
//!
//! Example:
//! ```rust
//! use crate::generated::nouns::{{ noun.name | trim_matches(pat='"') }}::{{ noun.name | trim_matches(pat='"') | title }}Commands;
//!
//! pub struct {{ noun.name | trim_matches(pat='"') | title }}Domain { /* your fields */ }
//!
//! impl {{ noun.name | trim_matches(pat='"') | title }}Commands for {{ noun.name | trim_matches(pat='"') | title }}Domain {
//!     // ... implement methods
//! }
//! ```

use crate::error::DomainError;
use crate::generated::types::*;

/// Trait defining all {{ noun.name | trim_matches(pat='"') }} commands
///
/// **IMPLEMENT THIS TRAIT** in `src/domain/{{ noun.name | trim_matches(pat='"') }}.rs`
///
/// This trait is regenerated from RDF. Your implementation in src/domain/ is safe.
pub trait {{ noun.name | trim_matches(pat='"') | title }}Commands {
{% for verb in sparql_results.verbs %}{% if verb.noun_name | trim_matches(pat='"') == noun.name | trim_matches(pat='"') %}
    /// {{ verb.description | default(value=verb.name) | trim_matches(pat='"') }}
    fn {{ verb.name | trim_matches(pat='"') }}(
        &self,
{% for arg in sparql_results.arguments %}{% if arg.verb_name | trim_matches(pat='"') == verb.name | trim_matches(pat='"') %}
        {{ arg.name | trim_matches(pat='"') }}: {{ arg.rust_type | trim_matches(pat='"') }},
{% endif %}{% endfor %}
    ) -> Result<impl serde::Serialize, DomainError>;

{% endif %}{% endfor %}
}

{% endfor %}
