//! Struct error definition

use syn::{Generics, Ident};

use super::HttpStatusValue;

use super::field::FieldDefinition;
use super::format_string::validate_no_optional_fields_in_message;

/// A validated struct error definition ready for code generation
///
/// Struct errors are single-variant errors that don't need enum wrapping.
/// They have the same attributes as enum variants but at the struct level.
#[derive(Debug, Clone)]
pub(crate) struct StructDefinition {
    /// The name of the struct
    pub(crate) name: Ident,

    /// Generic parameters of the struct
    pub(crate) generics: Generics,

    /// Error message from `#[error("...")]`
    pub(crate) error_message: String,

    /// Diagnostic code from `#[diagnostic(code(...))]`
    pub(crate) diagnostic_code: String,

    /// Optional help text from `#[diagnostic(help(...))]`
    pub(crate) help_text: Option<String>,

    /// Optional URL from `#[diagnostic(url(...))]`
    pub(crate) url: Option<String>,

    /// Optional severity from `#[diagnostic(severity(...))]`
    pub(crate) severity: Option<String>,

    /// Optional HTTP status from `#[http_status(...)]`
    pub(crate) http_status: Option<HttpStatusValue>,

    /// Optional JSON-RPC error code from `#[jsonrpc_code(...)]`
    pub(crate) jsonrpc_code: Option<i32>,

    /// Fields of this struct
    pub(crate) fields: Vec<FieldDefinition>,
}

impl StructDefinition {
    /// Validate the struct definition
    pub(crate) fn validate(&self) -> syn::Result<()> {
        if self.error_message.is_empty() {
            return Err(syn::Error::new_spanned(
                &self.name,
                "struct must have #[error(\"message\")] attribute",
            ));
        }

        validate_no_optional_fields_in_message(&self.error_message, &self.fields)?;

        Ok(())
    }
}
