use std::fs::File;
use std::io::{BufRead, BufReader};

use u_sort::collator::Collator;

#[test]
fn collation_test_non_ignorable() {
    let data = File::open("data/CollationTest_NON_IGNORABLE.txt")
        .map(BufReader::new)
        .expect("collation test data");

    let collator = Collator::default();

    let mut prev_sort_key = None;

    let mut order_errors = 0;
    let mut sort_key_errors = 0;

    'line: for (n, line) in data.lines().enumerate() {
        let line = line.expect("line");

        let line = line.trim_start();

        if line.is_empty() || line.starts_with('#') {
            continue;
        }

        let (chars, rest) = line
            .split_once(';')
            .expect("a semicolon separated test line");

        let mut surrogates = false;
        let test_string = chars
            .trim()
            .split(' ')
            .map(|x| u32::from_str_radix(x, 16).expect("a valid hex value"))
            .map(|x| match char::from_u32(x) {
                Some(ch) => ch,
                None => {
                    if (0xD800u32..=0xDFFF).contains(&x) {
                        surrogates = true;

                        ' '
                    } else {
                        panic!("{}", line)
                    }
                }
            })
            .collect::<String>();

        if surrogates {
            continue 'line;
        }

        let expected_sort_key = rest.rsplit(['[', ']']).nth(1).expect("sort key");

        let sort_key = collator.sort_key(&test_string);
        let fmt_sort_key = u_sort::fmt(&sort_key);

        if let Some(prev_sort_key) = prev_sort_key.take() {
            if sort_key < prev_sort_key {
                eprintln!(
                    "Error at line {}: {:?} [{}]",
                    n + 1,
                    test_string,
                    expected_sort_key
                );

                order_errors += 1;
            }
        }

        prev_sort_key = Some(sort_key);

        if fmt_sort_key != expected_sort_key {
            eprintln!(
                "Error at line {}: {:?} expected: [{}], got: [{}] ({})",
                n + 1,
                u_norm::nfd(&test_string).collect::<String>(),
                expected_sort_key,
                fmt_sort_key,
                line
            );

            sort_key_errors += 1;
        }
    }

    assert_eq!(order_errors, 0);
    assert_eq!(sort_key_errors, 0);
}
