const CEA608_MAX_COLUMNS: usize = 32;

/// Add odd parity bit (bit 7) to a 7-bit CEA-608 byte.
fn add_parity(byte: u8) -> u8 {
    let val = byte & 0x7F;
    if val.count_ones().is_multiple_of(2) {
        val | 0x80
    } else {
        val
    }
}

/// Build a CEA-608 sequence that erases displayed captions.
pub fn build_608_clear_sequence() -> Vec<(u8, u8)> {
    let mut pairs = Vec::new();
    let edm = (add_parity(0x14), add_parity(0x2C));
    pairs.push(edm);
    pairs.push(edm);
    pairs
}

/// Build CEA-608 field 1 byte pairs for pop-on captions.
/// Each pair is sent on one frame. Control codes are doubled per spec.
pub fn build_608_sequence(lines: &[&str]) -> Vec<(u8, u8)> {
    let mut pairs = Vec::new();

    let rcl = (add_parity(0x14), add_parity(0x20));
    pairs.push(rcl);
    pairs.push(rcl);

    let enm = (add_parity(0x14), add_parity(0x2E));
    pairs.push(enm);
    pairs.push(enm);

    let line_count = lines.len().min(2);
    for (i, line) in lines.iter().enumerate().take(2) {
        let line_len = line.len().min(CEA608_MAX_COLUMNS);

        let row_index = i + (2 - line_count);
        let pac = if row_index == 0 {
            (add_parity(0x13), add_parity(0x60))
        } else {
            (add_parity(0x14), add_parity(0x60))
        };
        pairs.push(pac);
        pairs.push(pac);

        let bytes = &line.as_bytes()[..line_len];
        for chunk in bytes.chunks(2) {
            let b1 = add_parity(chunk[0]);
            let b2 = if chunk.len() > 1 {
                add_parity(chunk[1])
            } else {
                add_parity(0x20)
            };
            pairs.push((b1, b2));
        }
    }

    let eoc = (add_parity(0x14), add_parity(0x2F));
    pairs.push(eoc);
    pairs.push(eoc);

    pairs
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn build_608_clear_sequence_is_edm_twice() {
        let pairs = build_608_clear_sequence();
        assert_eq!(pairs.len(), 2);
        assert_eq!(pairs[0], pairs[1]);
    }

    #[test]
    fn build_608_sequence_wraps_with_rcl_enm_and_eoc() {
        let pairs = build_608_sequence(&["HI"]);

        assert_eq!(pairs.len(), 9);
        assert_eq!(pairs[0], pairs[1]); // RCL doubled
        assert_eq!(pairs[2], pairs[3]); // ENM doubled
        assert_eq!(pairs[4], pairs[5]); // PAC doubled
        assert_eq!(pairs[7], pairs[8]); // EOC doubled
    }

    #[test]
    fn build_608_sequence_limits_to_two_lines_and_32_columns() {
        let long = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        let pairs = build_608_sequence(&[long, "B", "ignored"]);

        let expected_total = 4 + (2 + 16) + (2 + 1) + 2;
        assert_eq!(pairs.len(), expected_total);
    }
}
