//! [`ValidationErrors`] — structured validation error map.

use std::collections::HashMap;

use serde::Serialize;

/// Structured validation errors keyed by field name.
///
/// Serializes as `{ "field": ["message", …], … }`.
#[derive(Debug, Default, Clone, Serialize)]
pub struct ValidationErrors {
    #[serde(flatten)]
    inner: HashMap<String, Vec<String>>,
}

impl ValidationErrors {
    pub fn new() -> Self {
        Self::default()
    }

    /// Add an error message for `field`.
    pub fn add(&mut self, field: &str, msg: &str) {
        self.inner
            .entry(field.to_string())
            .or_default()
            .push(msg.to_string());
    }

    /// `true` when no errors have been recorded.
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Iterate over all `(field, messages)` pairs.
    pub fn iter(&self) -> impl Iterator<Item = (&str, &[String])> {
        self.inner.iter().map(|(k, v)| (k.as_str(), v.as_slice()))
    }

    /// Consume and return the inner map.
    pub fn into_inner(self) -> HashMap<String, Vec<String>> {
        self.inner
    }

    /// Return a new `ValidationErrors` with every key prefixed by `{pfx}.`.
    ///
    /// Used by nested-validation code to produce `address.zip` or `items[0].quantity` keys.
    pub fn prefix(self, pfx: &str) -> Self {
        let inner = self
            .inner
            .into_iter()
            .map(|(k, v)| (format!("{pfx}.{k}"), v))
            .collect();
        Self { inner }
    }

    /// Merge all errors from `other` into `self`.
    pub fn merge(&mut self, other: ValidationErrors) {
        for (k, msgs) in other.inner {
            self.inner.entry(k).or_default().extend(msgs);
        }
    }
}

impl std::fmt::Display for ValidationErrors {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for (field, msgs) in &self.inner {
            for msg in msgs {
                writeln!(f, "{field}: {msg}")?;
            }
        }
        Ok(())
    }
}

impl std::error::Error for ValidationErrors {}
