/*******************************************************************************
 *
 *    Copyright (c) 2026 Haixing Hu.
 *
 *    SPDX-License-Identifier: Apache-2.0
 *
 *    Licensed under the Apache License, Version 2.0.
 *
 ******************************************************************************/
//! Defines the coarse top-level JSON kinds used by constrained decode methods.
//!

use std::{
    fmt,
    str::FromStr,
};

use serde_json::Value;

/// Represents the top-level kind of a parsed JSON value.
///
/// The decoder uses this type to report whether the parsed value is an object,
/// an array, or any other scalar-like JSON value.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum JsonTopLevelKind {
    /// Indicates that the parsed top-level value is a JSON object.
    Object,
    /// Indicates that the parsed top-level value is a JSON array.
    Array,
    /// Indicates that the parsed top-level value is neither an object nor an
    /// array.
    Other,
}

impl JsonTopLevelKind {
    /// Classifies the top-level kind of `value`.
    ///
    /// This helper is used internally by constrained decode methods and may
    /// also be useful to callers inspecting decoded [`Value`] instances.
    #[inline]
    #[must_use]
    pub fn of(value: &Value) -> Self {
        match value {
            Value::Object(_) => Self::Object,
            Value::Array(_) => Self::Array,
            _ => Self::Other,
        }
    }
}

impl From<&Value> for JsonTopLevelKind {
    #[inline]
    fn from(value: &Value) -> Self {
        Self::of(value)
    }
}

impl fmt::Display for JsonTopLevelKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let name = match self {
            Self::Object => "object",
            Self::Array => "array",
            Self::Other => "other",
        };
        f.write_str(name)
    }
}

impl FromStr for JsonTopLevelKind {
    type Err = &'static str;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        if value.eq_ignore_ascii_case("object") {
            Ok(Self::Object)
        } else if value.eq_ignore_ascii_case("array") {
            Ok(Self::Array)
        } else if value.eq_ignore_ascii_case("other") {
            Ok(Self::Other)
        } else {
            Err("unknown JsonTopLevelKind")
        }
    }
}
