//! CSS escape decoding for identifier, hash, and string token text.
//!
//! Three token shapes drive the scan, tried in order at each position:
//! a unicode escape (`\` then 1 to 6 hex digits with an optional trailing
//! whitespace char), a single-char escape (`\` then one non-newline non-hex
//! char), or any other char copied as is.

/// Decode CSS escape sequences in `input`.
///
/// A unicode escape becomes the code point it names. A single-char escape
/// becomes the char after the backslash. Everything else is copied.
pub fn unescape(input: &str) -> String {
    let chars: Vec<char> = input.chars().collect();
    let mut out = String::with_capacity(input.len());
    let mut i = 0;
    while i < chars.len() {
        let c = chars[i];
        if c == '\\' && i + 1 < chars.len() {
            let next = chars[i + 1];
            if next.is_ascii_hexdigit() {
                // Unicode escape: up to 6 hex digits.
                let mut hex = String::new();
                let mut j = i + 1;
                while j < chars.len() && hex.len() < 6 && chars[j].is_ascii_hexdigit() {
                    hex.push(chars[j]);
                    j += 1;
                }
                // Skip one optional trailing whitespace char (matches the lexer
                // regex `(?:\r\n|[ \n\r\t\f])?`).
                if j < chars.len() {
                    let w = chars[j];
                    if w == '\r' && j + 1 < chars.len() && chars[j + 1] == '\n' {
                        j += 2;
                    } else if matches!(w, ' ' | '\n' | '\r' | '\t' | '\u{0C}') {
                        j += 1;
                    }
                }
                let code = u32::from_str_radix(&hex, 16).unwrap_or(0);
                match char::from_u32(code) {
                    Some(ch) => out.push(ch),
                    None => out.push('\u{FFFD}'),
                }
                i = j;
                continue;
            }
            if next != '\n' && next != '\r' && next != '\u{0C}' {
                // Single-char escape: emit the char after the backslash.
                out.push(next);
                i += 2;
                continue;
            }
        }
        out.push(c);
        i += 1;
    }
    out
}
