const fn str_clone<'a, const N: usize>(ss: &[&'a str]) -> [&'a str; N] {
    assert!(ss.len() == N);
    let mut buf = [""; N];
    let mut i = 0;
    while i < ss.len() {
        buf[i] = ss[i];
        i += 1;
    }
    buf
}

const fn str_sorted<'a, const N: usize>(ss: &[&'a str]) -> [&'a str; N] {
    let mut buf = str_clone(ss);

    let mut l = N;
    while l > 1 {
        let mut swapped = false;

        let mut i = 0;
        while i < l - 1 {
            let (lhs, rhs) = (buf[i], buf[i + 1]);
            if crate::compare!(>, lhs, rhs) {
                (buf[i], buf[i + 1]) = (rhs, lhs);
                swapped = true;
            }
            i += 1;
        }

        if !swapped {
            break;
        }

        l -= 1;
    }

    buf
}

pub struct Sorted<T>(pub T);

impl<'a> Sorted<&[&'a str]> {
    pub const fn output_len(&self) -> usize {
        self.0.len()
    }

    pub const fn const_eval<const N: usize>(&self) -> [&'a str; N] {
        str_sorted(self.0)
    }
}

impl<'a, const L: usize> Sorted<[&'a str; L]> {
    pub const fn output_len(&self) -> usize {
        L
    }

    pub const fn const_eval(&self) -> [&'a str; L] {
        str_sorted(&self.0)
    }
}

impl<'a, const L: usize> Sorted<&[&'a str; L]> {
    pub const fn output_len(&self) -> usize {
        L
    }

    pub const fn const_eval(&self) -> [&'a str; L] {
        str_sorted(self.0)
    }
}

/// Sorts string slices and returns a new array.
///
/// The input type must be one of:
/// + [`&[&str]`](slice)
/// + [`[&str; N]`](array)
/// + [`&[&str; N]`](array)
///
/// This macro is [const-context only](./index.html#const-context-only).
///
/// # Examples
///
/// ```rust
/// const SORTED1: &[&str] = &const_str::sorted!(["one", "two", "three"]);
/// assert_eq!(SORTED1, &["one", "three", "two"]);
///
/// const SORTED2: [&str; 3] = const_str::sorted!(["1", "2", "10"]);
/// assert_eq!(SORTED2, ["1", "10", "2"]);
/// ```
///
#[macro_export]
macro_rules! sorted {
    ($s:expr) => {{
        const N: usize = $crate::__ctfe::Sorted($s).output_len();
        const SS: [&str; N] = $crate::__ctfe::Sorted($s).const_eval();
        SS
    }};
}

#[cfg(test)]
mod tests {
    fn std_sorted<'a>(iter: impl IntoIterator<Item = &'a str>) -> Vec<&'a str> {
        let mut v: Vec<_> = iter.into_iter().collect();
        v.sort_unstable();
        v
    }

    #[test]
    fn test_sorted() {
        macro_rules! testcase {
            ($s:expr) => {
                let const_sorted = sorted!($s);
                let std_sorted = std_sorted($s);
                assert_eq!(const_sorted, &*std_sorted);
            };
        }

        testcase!([]);
        testcase!(["a"]);
        testcase!(["a", "a"]);
        testcase!(["b", "a"]);
        testcase!(["a", "b", "c"]);
        testcase!(["b", "a", "c"]);
        testcase!(["c", "b", "a"]);
        testcase!(["1", "2", "10", "20", "3"]);
    }

    #[test]
    fn test_sorted_runtime() {
        use super::*;

        // Runtime tests for Sorted
        let sorted1 = Sorted(&["c", "a", "b"]);
        assert_eq!(sorted1.output_len(), 3);
        let result1: [&str; 3] = sorted1.const_eval();
        assert_eq!(result1, ["a", "b", "c"]);

        let sorted2 = Sorted(&["z", "a", "m", "b"]);
        assert_eq!(sorted2.output_len(), 4);
        let result2: [&str; 4] = sorted2.const_eval();
        assert_eq!(result2, ["a", "b", "m", "z"]);

        let empty: &[&str] = &[];
        let sorted_empty = Sorted(empty);
        assert_eq!(sorted_empty.output_len(), 0);

        let sorted_single = Sorted(&["only"]);
        let result_single: [&str; 1] = sorted_single.const_eval();
        assert_eq!(result_single, ["only"]);

        let sorted_duplicates = Sorted(&["x", "x", "y"]);
        let result_dup: [&str; 3] = sorted_duplicates.const_eval();
        assert_eq!(result_dup, ["x", "x", "y"]);
    }

    #[test]
    fn test_sorted_different_types() {
        use super::*;

        // Test Sorted<[&str; L]> - covers lines 52-54 and 56-58
        let array: [&str; 3] = ["c", "a", "b"];
        let sorted_array = Sorted(array);
        assert_eq!(sorted_array.output_len(), 3);
        let result_array: [&str; 3] = sorted_array.const_eval();
        assert_eq!(result_array, ["a", "b", "c"]);
    }
}
