use super::*;

#[test]
fn xmltv_times_and_their_refusals() {
    assert_eq!(xmltv_time("20261029180000"), Ok(1_793_296_800_000));
    assert_eq!(xmltv_time("20261029200000 +0200"), Ok(1_793_296_800_000));
    assert_eq!(xmltv_time("20261029160000 -0200"), Ok(1_793_296_800_000));
    assert_eq!(xmltv_time("20261029180000 BST"), Err(Reason::ImportTimezoneUnknown));
    assert_eq!(xmltv_time("20261029180000 +2400"), Err(Reason::ImportTimezoneUnknown));
    assert_eq!(xmltv_time("202610291800"), Err(Reason::ImportTimeMalformed));
    assert_eq!(xmltv_time("20260230180000"), Err(Reason::ImportTimeMalformed));
    assert_eq!(xmltv_time("20280229180000").map(|_| ()), Ok(()));
    assert_eq!(xmltv_time("19700101000000 +0100"), Err(Reason::ImportTimeMalformed));
    assert_eq!(xmltv_time("20261029180000+0000"), Err(Reason::ImportTimeMalformed));
    assert_eq!(xmltv_format(1_793_296_800_000), "20261029180000 +0000");
}

#[test]
fn hls_date_times_and_durations() {
    assert_eq!(hls_date_time("2026-10-29T18:00:00Z"), Ok(1_793_296_800_000));
    assert_eq!(hls_date_time("2026-10-29T18:00:00.5Z"), Ok(1_793_296_800_500));
    assert_eq!(hls_date_time("2026-10-29T18:00:00.250000Z"), Ok(1_793_296_800_250));
    assert_eq!(hls_date_time("2026-10-29T18:00:00.2501Z"), Err(Reason::ImportTimeMalformed));
    assert_eq!(hls_date_time("2026-10-29T20:00:00+02:00"), Ok(1_793_296_800_000));
    assert_eq!(hls_date_time("2026-10-29T18:00:00"), Err(Reason::ImportTimezoneUnknown));
    assert_eq!(hls_date_time("2026-10-29 18:00:00Z"), Err(Reason::ImportTimeMalformed));
    assert_eq!(duration_ms("90.000"), Ok(90_000));
    assert_eq!(duration_ms("1.0005"), Err(Reason::ImportTimeMalformed));
    assert_eq!(duration_ms("-1"), Err(Reason::ImportTimeMalformed));
}

#[test]
fn a_document_type_declaration_is_skipped_once() {
    let ok = b"<?xml version=\"1.0\"?>\n<!-- c --><!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n<tv/>";
    assert_eq!(read_feed_xml(ok).map(|e| e.name), Some("tv".to_string()));
    assert!(read_feed_xml(b"<!DOCTYPE tv PUBLIC 'a' \"b\"><tv/>").is_some());
    assert!(read_feed_xml(b"<!DOCTYPE tv><tv/>").is_some());
    assert!(read_feed_xml(b"<!DOCTYPE tv [<!ENTITY x \"y\">]><tv/>").is_none(), "an internal subset is outside the subset");
    assert!(read_feed_xml(b"<!DOCTYPE tv><!DOCTYPE tv><tv/>").is_none(), "a second declaration is outside it");
    assert!(read_feed_xml(b"<!DOCTYPEtv><tv/>").is_none());
}

#[test]
fn every_reason_has_its_code() {
    for r in Reason::ADDED.iter().chain(Reason::REUSED) {
        assert_eq!(Reason::from_code(r.code()), Some(*r));
    }
}

#[test]
fn the_capability_is_the_registrys() {
    assert_eq!(CAPABILITY, crate::codecs::registry::CAP_VIDEO_LINEUP);
}

fn unhex_any(s: &str) -> Vec<u8> {
    (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()).collect()
}

/// The sample messages of ANSI/SCTE 35-1 2023r2 §14.2 (a `splice_insert()`) and §14.1 (a
/// `time_signal()`): each reads as live-events §4.3 reads form 1, the first's cue id is its
/// `splice_event_id` (0x4800008F), and the second's, a command with none, is the break id's.
#[test]
fn the_cue_id_is_a_splice_inserts_event_id() {
    let insert = unhex_any("FC302F000000000000FFFFF014054800008F7FEFFE7369C02EFE0052CCF500000000000A0008435545490000013562DBA30A");
    let signal = unhex_any("FC3034000000000000FFFFF00506FE72BD0050001E021C435545494800008E7FCF0001A599B00808000000002CA0A18A3402009AC9D17E");
    assert_eq!(insert.len(), 50);
    assert_eq!(import::cue_id("brk", Some(&insert)), 0x4800_008F);
    assert_ne!(import::cue_id("brk", Some(&signal)), 0x4800_008E);
    assert_eq!(import::cue_id("brk", Some(&signal)), import::cue_id("brk", None));
    let mut encrypted = insert.clone();
    encrypted[4] |= 0x80;
    assert_eq!(import::cue_id("brk", Some(&encrypted)), import::cue_id("brk", None), "an encrypted command is not read");
}
