#![cfg(all(feature = "skrifa", feature = "wgpu"))]

mod common;

use common::gpu::{GpuCtx, compare_font_render_gpu};
use klyff_msdf::MtsdfGpuWriter;

fn err_output_path(name: &str) -> std::path::PathBuf {
    [std::env!("CARGO_TARGET_TMPDIR"), name]
        .into_iter()
        .collect()
}

fn ref_image_path(name: &str, char_code: u32) -> std::path::PathBuf {
    [
        std::env!("CARGO_MANIFEST_DIR"),
        "tests",
        "ref",
        &format!("{name}_{char_code}.png"),
    ]
    .into_iter()
    .collect()
}

struct Harness {
    gpu: GpuCtx,
    writer: MtsdfGpuWriter,
}

impl Harness {
    fn new() -> Option<Self> {
        let gpu = GpuCtx::new()?;
        let writer = MtsdfGpuWriter::new(&gpu.device);
        Some(Self { gpu, writer })
    }
}

#[test]
fn icon_font() {
    let Some(mut h) = Harness::new() else {
        eprintln!("no wgpu adapter available; skipping gpu icon_font");
        return;
    };
    for c in [
        0xE000, 0xE002, 0xE00B, 0xE035, 0xE062, 0xE0C4, 0xE052, 0xE057, 0xE06F,
    ] {
        compare_font_render_gpu(
            &h.gpu,
            &mut h.writer,
            "Allkin",
            include_bytes!("../../../fonts/Allkin-Regular.ttf"),
            char::from_u32(c).expect("valid character code"),
            &ref_image_path("Allkin", c),
            &err_output_path("allkin_gpu_error"),
        );
    }
}

#[test]
fn cjk_font_ttf() {
    let Some(mut h) = Harness::new() else {
        eprintln!("no wgpu adapter available; skipping gpu cjk_font_ttf");
        return;
    };
    let chars = [
        '人', '你', '好', '世', '界', '中', '国', '日', '本', '汉', '字', '大', '小', '上', '下',
        '永', '龍', '鬱', '一', '二', '三', '十', '百', '千',
    ];
    for c in chars {
        compare_font_render_gpu(
            &h.gpu,
            &mut h.writer,
            "NotoSansSC",
            include_bytes!("../../../fonts/NotoSansSC-Regular.ttf"),
            c,
            &ref_image_path("NotoSansSC_ttf", c as u32),
            &err_output_path("notosanssc_ttf_gpu_error"),
        );
    }
}

#[test]
fn cjk_font_otf() {
    let Some(mut h) = Harness::new() else {
        eprintln!("no wgpu adapter available; skipping gpu cjk_font_otf");
        return;
    };
    let chars = [
        '人', '你', '好', '世', '界', '中', '国', '日', '本', '汉', '字', '大', '小', '上', '下',
        '永', '龍', '鬱', '一', '二', '三', '十', '百', '千',
    ];
    for c in chars {
        compare_font_render_gpu(
            &h.gpu,
            &mut h.writer,
            "NotoSansSC",
            include_bytes!("../../../fonts/NotoSansSC-Regular.otf"),
            c,
            &ref_image_path("NotoSansSC_otf", c as u32),
            &err_output_path("notosanssc_otf_gpu_error"),
        );
    }
}

#[test]
fn sans_font() {
    let Some(mut h) = Harness::new() else {
        eprintln!("no wgpu adapter available; skipping gpu sans_font");
        return;
    };
    let standard = 0x0021..=0x007E;
    let ext_ascii = 0x00A1..=0x017F;
    let special_chars = [
        0x00AE, 0x00D8, 0x004F, 0x00A4, 0x00DF, 0x0118, 0x0163, 0x0468, 0x046e, 0x0466, 0x0496,
        0x047a, 0x05e9, 0x05d0, 0xFFFC, 0xFFFD,
    ];
    let diacritics = 0x1EA0..=0x1EF9;
    for c in standard
        .into_iter()
        .chain(ext_ascii)
        .chain(special_chars)
        .chain(diacritics)
    {
        compare_font_render_gpu(
            &h.gpu,
            &mut h.writer,
            "OpenSans",
            include_bytes!("../../../fonts/OpenSans-Regular.ttf"),
            char::from_u32(c).expect("valid character code"),
            &ref_image_path("OpenSans", c),
            &err_output_path("opensans_gpu_error"),
        );
    }
}
