//! Shared helpers for the test suites.
//!
//! Reads the golden assets from disk. Tests rebuild the CSS and index assets
//! from the sequence set and compare against these files, which is an
//! independent transform rather than reading the embedded const back.

#![allow(dead_code)]

use std::path::PathBuf;

use emoji_test_regex_pattern::{EmojiVersion, OutputKind};

/// Every concrete version directory name, ascending.
pub const VERSIONS: &[&str] = &[
    "emoji-13.0",
    "emoji-13.1",
    "emoji-14.0",
    "emoji-15.0",
    "emoji-15.1",
    "emoji-16.0",
    "emoji-17.0",
];

/// The highest version. `latest` mirrors it.
pub const LATEST: &str = "emoji-17.0";

/// Map a directory name to the enum value.
pub fn version_of(dir: &str) -> EmojiVersion {
    match dir {
        "emoji-13.0" => EmojiVersion::V13_0,
        "emoji-13.1" => EmojiVersion::V13_1,
        "emoji-14.0" => EmojiVersion::V14_0,
        "emoji-15.0" => EmojiVersion::V15_0,
        "emoji-15.1" => EmojiVersion::V15_1,
        "emoji-16.0" => EmojiVersion::V16_0,
        "emoji-17.0" => EmojiVersion::V17_0,
        "latest" => EmojiVersion::Latest,
        other => panic!("unknown version dir {other}"),
    }
}

/// Read a golden asset from `assets/<dir>/<file>`.
pub fn golden(dir: &str, kind: OutputKind) -> String {
    let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    path.push("assets");
    path.push(dir);
    path.push(kind.file_name());
    std::fs::read_to_string(&path)
        .unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()))
}

/// The sorted sequence multiset for a version.
///
/// `index-strings.txt` is the default-sorted sequence list, duplicates and all.
/// Splitting it on newlines recovers that list. Callers re-sort as needed.
pub fn default_sorted_sequences(dir: &str) -> Vec<String> {
    let text = golden(dir, OutputKind::IndexStrings);
    let trimmed = text
        .strip_suffix('\n')
        .expect("index-strings ends with \\n");
    trimmed.split('\n').map(str::to_owned).collect()
}

/// Translate the `u`-flag JavaScript pattern into Rust `regex` syntax.
///
/// The `u`-flag pattern uses `\u{HEX}` for astral code points and `\uXXXX` for
/// BMP code points. Rust `regex` spells both `\x{HEX}`. This rewrite does not
/// change which strings the pattern matches. Rust `regex` matches on Unicode
/// scalar values, which lines up with the `u` flag.
pub fn js_u_to_rust(pattern: &str) -> String {
    let cs: Vec<char> = pattern.chars().collect();
    let mut out = String::with_capacity(pattern.len());
    let mut i = 0;
    while i < cs.len() {
        if cs[i] == '\\' && i + 1 < cs.len() && cs[i + 1] == 'u' {
            if i + 2 < cs.len() && cs[i + 2] == '{' {
                out.push_str("\\x{");
                i += 3;
                while i < cs.len() && cs[i] != '}' {
                    out.push(cs[i]);
                    i += 1;
                }
                out.push('}');
                i += 1;
            } else {
                let hex: String = cs[i + 2..i + 6].iter().collect();
                out.push_str("\\x{");
                out.push_str(&hex);
                out.push('}');
                i += 6;
            }
        } else {
            out.push(cs[i]);
            i += 1;
        }
    }
    out
}

/// The Emoji 13.0 `RGI_Emoji` set, one string per line.
pub fn lcd_rgi_emoji() -> Vec<String> {
    let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    path.push("tests");
    path.push("fixtures");
    path.push("rgi-emoji-13.0.txt");
    let text = std::fs::read_to_string(&path)
        .unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
    text.lines().map(str::to_owned).collect()
}
