/// Pulse wave channel for the NES APU
/// Generates square waves with variable duty cycle
use super::envelope::Envelope;
use super::length_counter::LengthCounter;
use crate::nes::apu::envelope::EnvelopeState;
use crate::trace_apu;
use serde::{Deserialize, Serialize};

/// APU pulse channel state for save-state support.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PulseState {
    pub timer: u16,
    pub timer_period: u16,
    pub length_counter: u8,
    pub length_counter_enabled: bool,
    pub length_counter_halt: bool,
    pub length_counter_pending_halt: Option<bool>,
    pub length_counter_reload_value: u8,
    pub length_counter_previous_value: u8,
    pub duty: u8,
    pub duty_position: u8,
    pub envelope: EnvelopeState,
    pub sweep_enabled: bool,
    pub sweep_period: u8,
    pub sweep_negate: bool,
    pub sweep_shift: u8,
    pub sweep_reload: bool,
    pub sweep_divider: u8,
}

pub struct Pulse {
    // Channel identifier (true = Pulse 1, false = Pulse 2)
    // Used for sweep complement mode: Pulse 1 uses ones' complement, Pulse 2 uses two's complement
    is_pulse1: bool,

    // Timer fields
    timer_period: u16,
    timer_counter: u16,

    // Sequencer fields
    duty_mode: u8,
    sequence_position: u8,

    // Envelope fields
    envelope: Envelope,

    // Length counter fields
    length_counter: LengthCounter,

    // Sweep unit fields
    sweep_enabled: bool,
    sweep_divider_period: u8,
    sweep_negate: bool,
    sweep_shift: u8,
    sweep_reload: bool,
    sweep_divider: u8,
}

/// Duty cycle sequence lookup tables
/// Sequencer starts at 0 and counts down (reads 0, 7, 6, 5, 4, 3, 2, 1)
const DUTY_SEQUENCES: [[u8; 8]; 4] = [
    [0, 0, 0, 0, 0, 0, 0, 1], // 12.5%
    [0, 0, 0, 0, 0, 0, 1, 1], // 25%
    [0, 0, 0, 0, 1, 1, 1, 1], // 50%
    [1, 1, 1, 1, 1, 1, 0, 0], // 25% negated
];

impl Default for Pulse {
    fn default() -> Self {
        Self::new(true) // Default to Pulse 1
    }
}

impl Pulse {
    /// Create a new Pulse channel
    ///
    /// # Arguments
    /// * `is_pulse1` - true for Pulse 1, false for Pulse 2 (affects sweep complement mode)
    pub fn new(is_pulse1: bool) -> Self {
        Self {
            is_pulse1,
            timer_period: 0,
            timer_counter: 0,
            duty_mode: 0,
            sequence_position: 0,
            envelope: Envelope::new(),
            length_counter: LengthCounter::new(),

            // Sweep unit fields
            sweep_enabled: false,
            sweep_divider_period: 0,
            sweep_negate: false,
            sweep_shift: 0,
            sweep_reload: false,
            sweep_divider: 0,
        }
    }

    /// Reset pulse channel to initial state (preserves is_pulse1 identity)
    pub fn reset(&mut self) {
        trace_apu!(2; "{} reset", if self.is_pulse1 { "pulse1" } else { "pulse2" });
        self.timer_period = 0;
        self.timer_counter = 0;
        self.duty_mode = 0;
        self.sequence_position = 0;
        self.envelope.reset();
        self.length_counter.reset();
        self.sweep_enabled = false;
        self.sweep_divider_period = 0;
        self.sweep_negate = false;
        self.sweep_shift = 0;
        self.sweep_reload = false;
        self.sweep_divider = 0;
    }

    /// Write to timer low register ($4002 for Pulse 1)
    pub fn write_timer_low(&mut self, value: u8) {
        self.timer_period = (self.timer_period & 0x0700) | (value as u16);
        trace_apu!(4; "{} write_timer_low value=0x{:02X} period=0x{:03X}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, value, self.timer_period);
    }

    /// Write to timer high register ($4003 bits 2-0 for Pulse 1)
    pub fn write_timer_high(&mut self, value: u8) {
        self.timer_period = (self.timer_period & 0x00FF) | (((value & 0x07) as u16) << 8);
        trace_apu!(4; "{} write_timer_high value=0x{:02X} period=0x{:03X}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, value, self.timer_period);
    }

    /// Get current timer period (for testing)
    #[cfg(test)]
    pub fn get_timer_period(&self) -> u16 {
        self.timer_period
    }

    /// Clock the timer (called every APU cycle, which is every 2 CPU cycles)
    pub fn clock_timer(&mut self) {
        if self.timer_counter == 0 {
            self.timer_counter = self.timer_period;
            self.clock_sequencer();
            trace_apu!(5; "{} clock_timer reload period=0x{:03X} seq_pos={}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, self.timer_period, self.sequence_position);
        } else {
            self.timer_counter -= 1;
        }
    }

    /// Clock the sequencer (decrements position)
    fn clock_sequencer(&mut self) {
        self.sequence_position = if self.sequence_position == 0 {
            7
        } else {
            self.sequence_position - 1
        };
    }

    /// Get the current sequencer output (0 or 1)
    pub fn get_sequencer_output(&self) -> u8 {
        DUTY_SEQUENCES[self.duty_mode as usize][self.sequence_position as usize]
    }

    /// Write duty cycle mode (bits 7-6 of $4000)
    #[cfg(test)]
    pub fn write_duty(&mut self, duty: u8) {
        self.duty_mode = duty & 0x03;
    }

    /// Write to $4000 register (duty, loop/halt, constant volume, volume/envelope period)
    pub fn write_control(&mut self, value: u8) {
        self.duty_mode = (value >> 6) & 0x03;
        self.length_counter.set_halt((value & 0x20) != 0); // Same bit as envelope loop
        self.envelope.write_control(value);
        trace_apu!(3; "{} write_control value=0x{:02X} duty={} halt={}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, value, self.duty_mode, (value & 0x20) != 0);
    }

    /// Write to $4003 register (loads length counter, sets start flag, sets timer high)
    pub fn write_length_counter_timer_high(&mut self, value: u8) {
        self.write_timer_high(value);
        // NESdev: writing $4003/$4007 resets the sequencer and timer divider.
        self.sequence_position = 0;
        self.timer_counter = self.timer_period;
        self.envelope.restart();
        // Load length counter from bits 7-3 (only if channel is enabled via $4015)
        let index = value >> 3;
        self.length_counter.load_from_index(index);
        trace_apu!(3; "{} write_length_counter_timer_high value=0x{:02X} length_index={}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, value, index);
    }

    /// Clock the envelope (called by quarter frame from frame counter)
    pub fn clock_envelope(&mut self) {
        self.envelope.clock();
    }

    /// Get the envelope volume output (0-15)
    pub fn get_envelope_volume(&self) -> u8 {
        self.envelope.volume()
    }

    /// Clock the length counter (called by half frame from frame counter)
    pub fn clock_length_counter(&mut self) {
        trace_apu!(
            3; "{} length_clock halt={} value={}",
            if self.is_pulse1 { "pulse1" } else { "pulse2" },
            self.length_counter.is_halted(),
            self.length_counter.value()
        );
        self.length_counter.clock();
    }

    pub fn apply_pending_length_reload(&mut self) {
        self.length_counter.reload_counter();
    }

    pub fn apply_pending_length_halt(&mut self) {
        self.length_counter.apply_pending_halt();
    }

    /// Get the current length counter value
    pub fn get_length_counter(&self) -> u8 {
        self.length_counter.value()
    }

    /// Clear the length counter to 0
    pub fn clear_length_counter(&mut self) {
        self.length_counter.clear();
    }

    /// Get the envelope start flag state
    #[cfg(test)]
    pub fn get_envelope_start_flag(&self) -> bool {
        self.envelope.debug_start_flag()
    }

    /// Get the sweep reload flag state
    #[cfg(test)]
    pub fn get_sweep_reload(&self) -> bool {
        self.sweep_reload
    }

    #[cfg(test)]
    pub fn debug_length_counter_halt(&self) -> bool {
        self.length_counter.is_halted()
    }

    #[cfg(test)]
    pub fn debug_length_counter_pending_halt(&self) -> Option<bool> {
        self.length_counter.pending_halt()
    }

    /// Set length counter enabled/disabled (from $4015)
    /// When disabled, the channel is silenced but the length counter value is preserved
    pub fn set_length_counter_enabled(&mut self, enabled: bool) {
        self.length_counter.set_enabled(enabled);
        trace_apu!(2; "{} set_length_counter_enabled {}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, enabled);
    }

    /// Get whether length counter is enabled (from $4015)
    pub fn is_length_counter_enabled(&self) -> bool {
        self.length_counter.is_enabled()
    }

    /// Write to sweep register ($4001/$4005)
    /// Bit 7: Enable flag
    /// Bits 6-4: Divider period (P), actual period = P + 1
    /// Bit 3: Negate flag (ones' complement for Pulse 1)
    /// Bits 2-0: Shift count
    pub fn write_sweep(&mut self, value: u8) {
        self.sweep_enabled = (value & 0x80) != 0;
        self.sweep_divider_period = ((value >> 4) & 0x07) + 1;
        self.sweep_negate = (value & 0x08) != 0;
        self.sweep_shift = value & 0x07;
        self.sweep_reload = true;
        trace_apu!(3; "{} write_sweep value=0x{:02X} enabled={} period={} negate={} shift={}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, value, self.sweep_enabled, self.sweep_divider_period, self.sweep_negate, self.sweep_shift);
    }

    /// Calculate target period for sweep
    ///
    /// Target = current period + change, where change depends on negate mode:
    /// - Non-negate: change = +(period >> shift)
    /// - Pulse 1 negate (ones' complement): change = -(period >> shift) - 1
    /// - Pulse 2 negate (two's complement): change = -(period >> shift)
    ///
    /// Negative results (pulse 1 negate underflow at shift=0) are clamped to 0.
    /// The muting check (target > $7FF) only applies when negate is false,
    /// matching real NES hardware behavior (Mesen reference).
    pub fn get_sweep_target_period(&self) -> u16 {
        let change = (self.timer_period >> self.sweep_shift) as i32;
        let current = self.timer_period as i32;
        let delta = if self.sweep_negate {
            if self.is_pulse1 {
                // Pulse 1: ones' complement (-change - 1)
                -change - 1
            } else {
                // Pulse 2: two's complement (-change)
                -change
            }
        } else {
            change
        };
        let target = current + delta;
        if target < 0 { 0 } else { target as u16 }
    }

    /// Check if sweep is muting the channel
    /// Mutes if: current period < 8 OR (negate is false AND target period > $7FF)
    /// The target > $7FF check only applies for upward sweep (negate=false),
    /// matching real NES hardware (Mesen reference).
    #[cfg(test)]
    pub fn is_sweep_muting(&self) -> bool {
        self.timer_period < 8 || (!self.sweep_negate && self.get_sweep_target_period() > 0x7FF)
    }

    /// Clock the sweep unit (called by half frame)
    pub fn clock_sweep(&mut self) {
        trace_apu!(1; "{} sweep_clock divider={} reload={} enabled={} shift={} period=0x{:03X}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, self.sweep_divider, self.sweep_reload, self.sweep_enabled, self.sweep_shift, self.timer_period);
        let target_period = self.get_sweep_target_period();
        let reload_value = self.sweep_divider_reload_value();
        trace_apu!(2; "{} sweep_state curr=0x{:03X} target=0x{:03X} divider={} reload={} enabled={} shift={}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, self.timer_period, target_period, self.sweep_divider, self.sweep_reload, self.sweep_enabled, self.sweep_shift);

        self.sweep_divider = self.sweep_divider.wrapping_sub(1);

        // Update period when divider reaches 0
        if self.sweep_divider == 0 {
            if !self.sweep_enabled {
                trace_apu!(1; "{} sweep_skip disabled", if self.is_pulse1 { "pulse1" } else { "pulse2" });
            } else if self.sweep_shift == 0 {
                trace_apu!(1; "{} sweep_skip shift=0", if self.is_pulse1 { "pulse1" } else { "pulse2" });
            } else if self.timer_period < 8 || target_period > 0x7FF {
                trace_apu!(1; "{} sweep_mute curr=0x{:03X} target=0x{:03X}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, self.timer_period, target_period);
            } else {
                self.timer_period = target_period;
                self.timer_counter = self.timer_period;
                trace_apu!(5; "{} sweep_update period=0x{:03X}", if self.is_pulse1 { "pulse1" } else { "pulse2" }, self.timer_period);
            }
            self.sweep_divider = reload_value;
        }

        if self.sweep_reload {
            self.sweep_divider = reload_value;
            self.sweep_reload = false;
        }
    }

    fn sweep_divider_reload_value(&self) -> u8 {
        self.sweep_divider_period
    }

    /// Get the current output sample from the pulse channel
    /// Returns envelope volume (0-15) if playing, or 0 if muted
    ///
    /// Channel is muted (outputs 0) if ANY of these conditions are true:
    /// 1. Sequencer output is 0 (duty cycle low point)
    /// 2. Length counter is 0
    /// 3. Timer period < 8
    /// 4. Sweep negate is false AND target period > $7FF
    pub fn output(&self) -> u8 {
        // Check all muting conditions
        let target_period = self.get_sweep_target_period();
        if self.get_sequencer_output() == 0
            || !self.length_counter.is_enabled() // Channel disabled via $4015
            || self.length_counter.value() == 0
            || self.timer_period < 8
            || (!self.sweep_negate && target_period > 0x7FF)
        {
            0
        } else {
            self.get_envelope_volume()
        }
    }

    /// Capture the current pulse channel state for save-state.
    pub fn capture_state(&self) -> PulseState {
        PulseState {
            timer: self.timer_counter,
            timer_period: self.timer_period,
            length_counter: self.length_counter.value(),
            length_counter_enabled: self.length_counter.is_enabled(),
            length_counter_halt: self.length_counter.is_halted(),
            length_counter_pending_halt: self.length_counter.pending_halt(),
            length_counter_reload_value: self.length_counter.reload_value(),
            length_counter_previous_value: self.length_counter.previous_value(),
            duty: self.duty_mode,
            duty_position: self.sequence_position,
            envelope: self.envelope.capture_state(),
            sweep_enabled: self.sweep_enabled,
            sweep_period: self.sweep_divider_period,
            sweep_negate: self.sweep_negate,
            sweep_shift: self.sweep_shift,
            sweep_reload: self.sweep_reload,
            sweep_divider: self.sweep_divider,
        }
    }

    /// Restore pulse channel state from a save-state.
    pub fn restore_state(&mut self, state: &PulseState) {
        self.timer_counter = state.timer;
        self.timer_period = state.timer_period;
        self.length_counter.set_value(state.length_counter);
        if state.length_counter_enabled {
            self.length_counter.enable();
        } else {
            self.length_counter.disable();
        }
        self.length_counter
            .set_halt_state(state.length_counter_halt, state.length_counter_pending_halt);
        self.length_counter.set_reload_state(
            state.length_counter_reload_value,
            state.length_counter_previous_value,
        );
        self.duty_mode = state.duty;
        self.sequence_position = state.duty_position;
        self.envelope.restore_state(&state.envelope);
        self.sweep_enabled = state.sweep_enabled;
        self.sweep_divider_period = state.sweep_period;
        self.sweep_negate = state.sweep_negate;
        self.sweep_shift = state.sweep_shift;
        self.sweep_reload = state.sweep_reload;
        self.sweep_divider = state.sweep_divider;
    }
}

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

    fn write_length(pulse: &mut Pulse, value: u8) {
        pulse.write_length_counter_timer_high(value);
        pulse.apply_pending_length_reload();
    }

    #[test]
    fn test_pulse_new() {
        let pulse = Pulse::default();
        assert_eq!(pulse.timer_period, 0);
        assert_eq!(pulse.sequence_position, 0);
    }

    #[test]
    fn test_write_timer_low() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0xAB);
        assert_eq!(pulse.timer_period, 0xAB);
    }

    #[test]
    fn test_write_timer_high() {
        let mut pulse = Pulse::default();
        pulse.write_timer_high(0x05);
        assert_eq!(pulse.timer_period, 0x0500);
    }

    #[test]
    fn test_write_timer_combined() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0xCD);
        pulse.write_timer_high(0x07);
        assert_eq!(pulse.timer_period, 0x07CD);
    }

    #[test]
    fn test_timer_high_masks_upper_bits() {
        let mut pulse = Pulse::default();
        pulse.write_timer_high(0xFF); // Only bits 2-0 should be used
        assert_eq!(pulse.timer_period, 0x0700);
    }

    #[test]
    fn test_sequencer_starts_at_zero() {
        let pulse = Pulse::default();
        assert_eq!(pulse.sequence_position, 0);
    }

    #[test]
    fn test_sequencer_counts_down() {
        let mut pulse = Pulse {
            timer_period: 0,
            ..Default::default()
        };

        // Initial position is 0, clock should move to 7
        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 7);

        // Then count down 7, 6, 5, 4, 3, 2, 1, 0
        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 6);

        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 5);

        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 4);

        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 3);

        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 2);

        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 1);

        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 0);

        // Should wrap back to 7
        pulse.clock_timer();
        assert_eq!(pulse.sequence_position, 7);
    }

    #[test]
    fn test_timer_countdown() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(3);

        // Timer starts at period value
        assert_eq!(pulse.timer_counter, 0);

        // First clock: counter = 0, reload to 3, clock sequencer
        pulse.clock_timer();
        assert_eq!(pulse.timer_counter, 3);
        assert_eq!(pulse.sequence_position, 7);

        // Count down: 3, 2, 1, 0
        pulse.clock_timer();
        assert_eq!(pulse.timer_counter, 2);
        assert_eq!(pulse.sequence_position, 7); // Sequencer unchanged

        pulse.clock_timer();
        assert_eq!(pulse.timer_counter, 1);

        pulse.clock_timer();
        assert_eq!(pulse.timer_counter, 0);

        // Next clock: reload and clock sequencer
        pulse.clock_timer();
        assert_eq!(pulse.timer_counter, 3);
        assert_eq!(pulse.sequence_position, 6);
    }

    #[test]
    fn test_duty_cycle_0_12_5_percent() {
        let mut pulse = Pulse::default();
        pulse.write_duty(0);

        // Duty 0: [0,0,0,0,0,0,0,1]
        // Sequencer reads: 0,7,6,5,4,3,2,1
        assert_eq!(pulse.get_sequencer_output(), 0); // Position 0

        pulse.sequence_position = 7;
        assert_eq!(pulse.get_sequencer_output(), 1); // Position 7

        pulse.sequence_position = 6;
        assert_eq!(pulse.get_sequencer_output(), 0); // Position 6

        pulse.sequence_position = 1;
        assert_eq!(pulse.get_sequencer_output(), 0); // Position 1
    }

    #[test]
    fn test_duty_cycle_1_25_percent() {
        let mut pulse = Pulse::default();
        pulse.write_duty(1);

        // Duty 1: [0,0,0,0,0,0,1,1]
        pulse.sequence_position = 7;
        assert_eq!(pulse.get_sequencer_output(), 1); // Position 7

        pulse.sequence_position = 6;
        assert_eq!(pulse.get_sequencer_output(), 1); // Position 6

        pulse.sequence_position = 5;
        assert_eq!(pulse.get_sequencer_output(), 0); // Position 5
    }

    #[test]
    fn test_duty_cycle_2_50_percent() {
        let mut pulse = Pulse::default();
        pulse.write_duty(2);

        // Duty 2: [0,0,0,0,1,1,1,1]
        pulse.sequence_position = 7;
        assert_eq!(pulse.get_sequencer_output(), 1);

        pulse.sequence_position = 4;
        assert_eq!(pulse.get_sequencer_output(), 1);

        pulse.sequence_position = 3;
        assert_eq!(pulse.get_sequencer_output(), 0);

        pulse.sequence_position = 0;
        assert_eq!(pulse.get_sequencer_output(), 0);
    }

    #[test]
    fn test_duty_cycle_3_25_percent_negated() {
        let mut pulse = Pulse::default();
        pulse.write_duty(3);

        // Duty 3: [1,1,1,1,1,1,0,0]
        pulse.sequence_position = 0;
        assert_eq!(pulse.get_sequencer_output(), 1);

        pulse.sequence_position = 5;
        assert_eq!(pulse.get_sequencer_output(), 1);

        pulse.sequence_position = 6;
        assert_eq!(pulse.get_sequencer_output(), 0);

        pulse.sequence_position = 7;
        assert_eq!(pulse.get_sequencer_output(), 0);
    }

    #[test]
    fn test_duty_write_masks_upper_bits() {
        let mut pulse = Pulse::default();
        pulse.write_duty(0xFF); // Only bits 1-0 should be used
        assert_eq!(pulse.duty_mode, 3);
    }

    // Envelope Generator Tests

    #[test]
    fn test_envelope_constant_volume_mode() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0001_1010); // Constant volume flag set, volume = 10
        assert_eq!(pulse.get_envelope_volume(), 10);

        // Clock envelope - output should remain constant in constant volume mode
        pulse.clock_envelope();
        assert_eq!(pulse.get_envelope_volume(), 10);
    }

    #[test]
    fn test_envelope_decay_mode() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0000_0000); // Decay mode, period = 0

        // Start flag not set, decay level starts at 0
        assert_eq!(pulse.get_envelope_volume(), 0);

        // Set start flag
        pulse.envelope.restart();
        pulse.clock_envelope();

        // Should reset to 15
        assert_eq!(pulse.get_envelope_volume(), 15);

        // Clock envelope - divider = 0, so should decrement decay level
        pulse.clock_envelope();
        assert_eq!(pulse.get_envelope_volume(), 14);

        pulse.clock_envelope();
        assert_eq!(pulse.get_envelope_volume(), 13);
    }

    #[test]
    fn test_envelope_start_flag_on_write() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0000_0000);

        assert!(!pulse.get_envelope_start_flag());

        write_length(&mut pulse, 0x00);
        assert!(pulse.get_envelope_start_flag());
    }

    #[test]
    fn test_envelope_divider_period() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0000_0010); // Period = 2 (divider period = 3)
        pulse.envelope.restart();
        pulse.clock_envelope();

        // Start flag cleared, decay level = 15, divider = 2
        assert_eq!(pulse.envelope.debug_counter(), 15);
        assert_eq!(pulse.envelope.debug_divider(), 2);

        // Clock: divider 2 -> 1
        pulse.clock_envelope();
        assert_eq!(pulse.envelope.debug_counter(), 15);
        assert_eq!(pulse.envelope.debug_divider(), 1);

        // Clock: divider 1 -> 0
        pulse.clock_envelope();
        assert_eq!(pulse.envelope.debug_counter(), 15);
        assert_eq!(pulse.envelope.debug_divider(), 0);

        // Clock: divider = 0, reload to 2, decrement decay level 15 -> 14
        pulse.clock_envelope();
        assert_eq!(pulse.envelope.debug_counter(), 14);
        assert_eq!(pulse.envelope.debug_divider(), 2);
    }

    #[test]
    fn test_envelope_loop_flag() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0010_0000); // Loop flag set, period = 0
        pulse.envelope.restart();
        pulse.clock_envelope();

        // With period = 0, divider is always 0, so decay decrements every clock
        // Decay from 15 to 0
        for expected in (0..=15).rev() {
            assert_eq!(pulse.envelope.debug_counter(), expected);
            pulse.clock_envelope();
        }

        // At 0, with loop flag, should have reloaded to 15
        assert_eq!(pulse.envelope.debug_counter(), 15);
    }

    #[test]
    fn test_envelope_no_loop_stays_at_zero() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0000_0000); // No loop, period = 0
        pulse.envelope.restart();
        pulse.clock_envelope();

        // Decay from 15 to 0
        for _ in 0..15 {
            pulse.clock_envelope();
        }

        assert_eq!(pulse.envelope.debug_counter(), 0);

        // Should stay at 0 without loop
        pulse.clock_envelope();
        assert_eq!(pulse.envelope.debug_counter(), 0);

        pulse.clock_envelope();
        assert_eq!(pulse.envelope.debug_counter(), 0);
    }

    #[test]
    fn test_write_control_parses_all_fields() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b1111_1010);
        // Bits 7-6: duty = 11 (3)
        // Bit 5: loop flag = 1
        // Bit 4: constant volume = 1
        // Bits 3-0: volume/period = 1010 (10)

        assert_eq!(pulse.duty_mode, 3);
        assert!(pulse.envelope.debug_loop_flag());
        assert!(pulse.envelope.debug_disable_flag());
        assert_eq!(pulse.envelope.debug_n(), 10);
    }

    #[test]
    fn test_envelope_constant_volume_still_updates_decay() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0001_0101); // Constant volume, period = 5
        pulse.envelope.restart();

        pulse.clock_envelope();
        assert_eq!(pulse.envelope.debug_counter(), 15);
        assert_eq!(pulse.get_envelope_volume(), 5); // Returns constant volume

        // Even in constant volume mode, decay level is updated
        for _ in 0..6 {
            pulse.clock_envelope();
        }
        assert_eq!(pulse.envelope.debug_counter(), 14);
        assert_eq!(pulse.get_envelope_volume(), 5); // Still returns constant volume
    }

    // Length Counter Tests

    #[test]
    fn test_length_counter_load_values() {
        let mut pulse = Pulse::default();
        pulse.set_length_counter_enabled(true);

        // Test all 32 load values
        let expected = [
            10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20,
            96, 22, 192, 24, 72, 26, 16, 28, 32, 30,
        ];

        for (i, &expected_value) in expected.iter().enumerate() {
            let value = (i as u8) << 3; // Put index in bits 7-3
            write_length(&mut pulse, value);
            assert_eq!(
                pulse.get_length_counter(),
                expected_value,
                "Failed for index {}",
                i
            );
        }
    }

    #[test]
    fn test_length_counter_decrements() {
        let mut pulse = Pulse::default();
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b00001_000); // Load value 2 (index 1)
        assert_eq!(pulse.get_length_counter(), 254);

        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 253);

        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 252);
    }

    #[test]
    fn test_length_counter_halt_flag() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0010_0000); // Set halt flag
        pulse.apply_pending_length_halt();
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b00010_000); // Load value 20 (index 2)

        assert_eq!(pulse.get_length_counter(), 20);

        // Clock should not decrement when halted
        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 20);

        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 20);
    }

    #[test]
    fn test_length_counter_stops_at_zero() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0000_0000); // No halt
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b00011_000); // Load value 2 (index 3)

        assert_eq!(pulse.get_length_counter(), 2);

        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 1);

        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 0);

        // Should not go below zero
        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 0);
    }

    #[test]
    fn test_length_counter_can_be_reloaded() {
        let mut pulse = Pulse::default();
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b00100_000); // Load value 40 (index 4)
        assert_eq!(pulse.get_length_counter(), 40);

        // Clock a few times
        pulse.clock_length_counter();
        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 38);

        // Reload with different value
        write_length(&mut pulse, 0b00000_000); // Load value 10 (index 0)
        assert_eq!(pulse.get_length_counter(), 10);
    }

    #[test]
    fn test_length_counter_halt_flag_shared_with_envelope_loop() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0010_0000); // Bit 5 set
        pulse.apply_pending_length_halt();

        // Both flags should be set from same bit
        assert!(pulse.length_counter.is_halted());
        assert!(pulse.envelope.debug_loop_flag());

        pulse.write_control(0b0000_0000); // Bit 5 clear
        pulse.apply_pending_length_halt();

        assert!(!pulse.length_counter.is_halted());
        assert!(!pulse.envelope.debug_loop_flag());
    }

    #[test]
    fn test_set_length_counter_enabled() {
        let mut pulse = Pulse::default();
        // Enable first, then load
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b01010_000); // Load some value
        assert_eq!(pulse.get_length_counter(), 60);

        // Disabling via $4015 clears the length counter
        pulse.set_length_counter_enabled(false);
        assert_eq!(pulse.get_length_counter(), 0);

        // Enable again - counter stays at 0 until reloaded
        pulse.set_length_counter_enabled(true);
        assert_eq!(pulse.get_length_counter(), 0);

        // Now we can load again since it's enabled
        write_length(&mut pulse, 0b00100_000); // Load different value
        assert_eq!(pulse.get_length_counter(), 40);
    }

    #[test]
    fn test_length_counter_with_halt_then_unhalt() {
        let mut pulse = Pulse::default();
        pulse.write_control(0b0010_0000); // Halt flag set
        pulse.apply_pending_length_halt();
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b00000_000); // Load 10

        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 10); // Halted, no change

        // Clear halt flag
        pulse.write_control(0b0000_0000);
        pulse.apply_pending_length_halt();

        pulse.clock_length_counter();
        assert_eq!(pulse.get_length_counter(), 9); // Now decrements
    }

    // Sweep unit tests

    #[test]
    fn test_sweep_initial_state() {
        let pulse = Pulse::default();
        // Initial period is 0, which is < 8, so it should be muting
        assert!(pulse.is_sweep_muting());
    }

    #[test]
    fn test_sweep_write_register() {
        let mut pulse = Pulse::default();
        // Enable=1, Period=3, Negate=1, Shift=2
        // Binary: 1_011_1_010
        pulse.write_sweep(0b1011_1010);

        // Should set reload flag (tested by observing divider reload on next clock)
        pulse.clock_sweep();
        // After first clock with reload flag, divider should be period (3)
    }

    #[test]
    fn test_sweep_reload_defers_first_update() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x10);
        pulse.write_timer_high(0x00); // Period = 16 (0x10)
        pulse.write_sweep(0b1011_0001); // Enable, period=3, no negate, shift=1

        // Target = 16 + (16 >> 1) = 16 + 8 = 24
        assert_eq!(pulse.get_sweep_target_period(), 24);

        // First clock reloads divider due to reload flag, no update yet
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 16);
        assert_eq!(pulse.sweep_divider, 4);

        // Four more clocks to count down divider (period = 4 half-frames)
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 16);
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 16);
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 16);

        // Next clock should update period
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 24);
    }

    #[test]
    fn test_sweep_target_period_no_negate() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x04);
        pulse.write_timer_high(0x00); // Period = 4
        pulse.write_sweep(0b1000_0001); // Enable, period=0, no negate, shift=1

        // Target = current + (current >> shift)
        // Target = 4 + (4 >> 1) = 4 + 2 = 6
        assert_eq!(pulse.get_sweep_target_period(), 6);
    }

    #[test]
    fn test_sweep_target_period_with_negate_ones_complement() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x14);
        pulse.write_timer_high(0x00); // Period = 20 (0x14)
        pulse.write_sweep(0b1000_1001); // Enable, period=0, negate=1, shift=1

        // Change = 20 >> 1 = 10
        // Ones' complement: -10 - 1 = -11
        // Target = 20 + (-11) = 9
        assert_eq!(pulse.get_sweep_target_period(), 9);
    }

    #[test]
    fn test_sweep_target_period_negate_with_shift_0() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x14);
        pulse.write_timer_high(0x00); // Period = 20 (0x14)
        pulse.write_sweep(0b1000_1000); // Enable, period=0, negate=1, shift=0

        // Change = 20 >> 0 = 20
        // Ones' complement: -20 - 1 = -21
        // Target = 20 + (-21) = -1, clamps to 0
        assert_eq!(pulse.get_sweep_target_period(), 0);
    }

    #[test]
    fn test_sweep_muting_period_less_than_8() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x07);
        pulse.write_timer_high(0x00); // Period = 7

        assert!(pulse.is_sweep_muting()); // Period < 8 should mute

        pulse.write_timer_low(0x08);
        pulse.write_timer_high(0x00); // Period = 8
        assert!(!pulse.is_sweep_muting()); // Period = 8 should not mute
    }

    #[test]
    fn test_sweep_muting_target_greater_than_7ff() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0xFF);
        pulse.write_timer_high(0b000_11111); // Period = $7FF
        pulse.write_sweep(0b1000_0001); // Enable, period=0, no negate, shift=1

        // Target = $7FF + ($7FF >> 1) = $7FF + $3FF = $BFF > $7FF
        assert!(pulse.is_sweep_muting());
    }

    #[test]
    fn test_sweep_divider_reload() {
        let mut pulse = Pulse::default();
        pulse.write_sweep(0b1011_0000); // Enable, period=3, no negate, shift=0

        // First clock should reload divider (reload flag set by write)
        pulse.clock_sweep();
        // Divider should now be 3

        // Clock 3 more times to count down divider
        pulse.clock_sweep(); // divider = 2
        pulse.clock_sweep(); // divider = 1
        pulse.clock_sweep(); // divider = 0, should reload to 3

        // This behavior is hard to observe without internal state access,
        // but we can test period update behavior
    }

    #[test]
    fn test_sweep_divider_period_is_p_plus_one() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x10);
        pulse.write_timer_high(0x00); // Period = 16 (0x10)
        pulse.write_sweep(0b1001_0001); // Enable, period=1, no negate, shift=1

        // First clock reloads divider, no update yet
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 16);

        // Divider period is P+1 (2 half-frames)
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 16);
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 24);

        // Next half-frames should update again after two more clocks
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 24);
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 36);
    }

    #[test]
    fn test_write_length_does_not_reset_sweep_divider() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x10);
        pulse.write_timer_high(0x00); // Period = 16 (0x10)
        pulse.write_sweep(0b1001_0001); // Enable, period=1, no negate, shift=1

        // Prime divider to 1 by advancing to just before an update.
        pulse.clock_sweep();
        pulse.clock_sweep();

        // Writing $4003/$4007 should NOT reset the sweep divider
        pulse.write_length_counter_timer_high(0x00);

        // Next sweep clock should update immediately (divider should remain at 1)
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 24);
    }

    #[test]
    fn test_sweep_period_update_when_enabled() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x10);
        pulse.write_timer_high(0x00); // Period = 16 (0x10)
        pulse.write_sweep(0b1000_0001); // Enable, period=0, no negate, shift=1

        // Target = 16 + (16 >> 1) = 16 + 8 = 24
        assert_eq!(pulse.get_sweep_target_period(), 24);

        // First clock reloads divider, no update yet
        pulse.clock_sweep();
        assert_eq!(
            pulse.get_timer_period(),
            16,
            "Period should not update on first clock"
        );

        // Second clock: period should update (P=0 means divider period = 1)
        pulse.clock_sweep();
        assert_eq!(
            pulse.get_timer_period(),
            24,
            "Period should update to sweep target on second clock"
        );

        // Third clock: should update again
        pulse.clock_sweep();
        assert_eq!(
            pulse.get_timer_period(),
            36,
            "Period should update to sweep target on third clock"
        );
    }

    #[test]
    fn test_sweep_no_update_when_disabled() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x10);
        pulse.write_timer_high(0x00); // Period = 16 (0x10)
        pulse.write_sweep(0b0000_0001); // Disabled, shift=1

        pulse.clock_sweep();
        pulse.clock_sweep();

        // Period should remain 16 (sweep disabled)
        assert_eq!(pulse.get_timer_period(), 16);
    }

    #[test]
    fn test_sweep_no_update_when_shift_zero() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x10);
        pulse.write_timer_high(0x00); // Period = 16 (0x10)
        pulse.write_sweep(0b1000_0000); // Enable, shift=0

        pulse.clock_sweep();
        pulse.clock_sweep();

        // Period should remain 16 (shift=0 means no update)
        assert_eq!(pulse.get_timer_period(), 16);
    }

    #[test]
    fn test_sweep_no_update_when_muting() {
        let mut pulse = Pulse::default();
        pulse.write_timer_low(0x07);
        pulse.write_timer_high(0x00); // Period = 7 (muted, < 8)
        pulse.write_sweep(0b1000_0001); // Enable, shift=1

        assert!(pulse.is_sweep_muting());

        pulse.clock_sweep();
        pulse.clock_sweep();

        // Period should remain 7 (muting prevents update)
        assert_eq!(pulse.get_timer_period(), 7);
    }

    // Output logic and integration tests

    #[test]
    fn test_output_when_all_conditions_met() {
        let mut pulse = Pulse::default();

        // Setup: duty 50%, constant volume 10, period 100, length counter loaded
        pulse.write_control(0b1011_1010); // Duty 50%, constant volume, volume=10
        pulse.write_timer_low(0x64); // Period = 100
        pulse.write_timer_high(0x00);
        write_length(&mut pulse, 0b00000_000); // Load length counter (index 0 = 10)

        // Advance to a point where sequencer outputs 1
        for _ in 0..=100 {
            pulse.clock_timer();
        }

        // Should output volume (10) when sequencer is high
        let output = pulse.output();
        assert!(output == 10 || output == 0); // Depends on sequencer position
    }

    #[test]
    fn test_output_silenced_when_sequencer_zero() {
        let mut pulse = Pulse::default();

        // Setup: duty 12.5% (mostly zeros), constant volume 15, period 100
        pulse.write_control(0b0001_1111); // Duty 12.5%, constant volume, volume=15
        pulse.write_timer_low(0x64);
        pulse.write_timer_high(0x00);
        write_length(&mut pulse, 0b00000_000); // Index 0 = 10

        // Step until sequencer is at 0
        // Sequencer reads in reverse: 0,7,6,5,4,3,2,1
        // Duty 12.5%: [0,0,0,0,0,0,0,1]
        // Most positions should be 0
        for _ in 0..102 {
            pulse.clock_timer();
        }

        // At some point output should be 0 due to sequencer
        let mut found_zero = false;
        for _ in 0..8 {
            if pulse.output() == 0 {
                found_zero = true;
                break;
            }
            pulse.clock_timer();
        }
        assert!(found_zero);
    }

    #[test]
    fn test_output_silenced_when_length_counter_zero() {
        let mut pulse = Pulse::default();

        // Setup with valid conditions but length counter = 0
        pulse.write_control(0b1011_1111); // Duty 50%, constant volume=15
        pulse.write_timer_low(0x64);
        pulse.write_timer_high(0x00);
        // Don't load length counter, it stays at 0

        assert_eq!(pulse.output(), 0);
    }

    #[test]
    fn test_output_silenced_when_timer_period_less_than_8() {
        let mut pulse = Pulse::default();

        // Setup with period < 8
        pulse.write_control(0b1011_1111); // Duty 50%, constant volume=15
        pulse.write_timer_low(0x07); // Period = 7 (< 8)
        pulse.write_timer_high(0x00);
        write_length(&mut pulse, 0b00000_000); // Load length counter (index 0 = 10)

        assert_eq!(pulse.output(), 0);
    }

    #[test]
    fn test_output_silenced_when_sweep_overflow() {
        let mut pulse = Pulse::default();

        // Setup with sweep that causes overflow
        pulse.write_control(0b1011_1111); // Duty 50%, constant volume=15
        write_length(&mut pulse, 0b00000_111); // Index 0, sets timer high to 7
        pulse.write_timer_low(0xFF); // Set low 8 bits -> Period = $7FF
        pulse.write_sweep(0b1000_0001); // Enable, shift=1 (will overflow)

        // Target = $7FF + ($7FF >> 1) = $7FF + $3FF = $BFE > $7FF
        assert!(pulse.is_sweep_muting());
        assert_eq!(pulse.output(), 0);
    }

    #[test]
    fn test_output_uses_envelope_volume() {
        let mut pulse = Pulse::default();

        // Setup with decay mode envelope
        pulse.write_control(0b1000_0101); // Duty 50%, decay mode, period=5
        pulse.write_timer_low(0x64);
        pulse.write_timer_high(0x00);
        write_length(&mut pulse, 0b00000_000); // Sets start flag (index 0 = 10)

        // Clock envelope to start it
        pulse.clock_envelope();

        // Envelope should start at 15
        assert_eq!(pulse.get_envelope_volume(), 15);

        // Output might be 15 or 0 depending on sequencer
        let output = pulse.output();
        assert!(output == 15 || output == 0);
    }

    #[test]
    fn test_integration_full_waveform_cycle() {
        let mut pulse = Pulse::default();

        // Setup: 50% duty cycle, constant volume 8, period 10
        pulse.write_control(0b1001_1000); // Duty 50%, constant volume=8
        pulse.write_timer_low(0x0A); // Period = 10
        pulse.write_timer_high(0x00);
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b00000_000); // Index 0 = 10

        // Run through one complete waveform cycle (8 steps)
        let mut outputs = Vec::new();
        for _ in 0..8 {
            outputs.push(pulse.output());
            // Clock timer to advance through period
            for _ in 0..=10 {
                pulse.clock_timer();
            }
        }

        // Should see mix of 8s and 0s (50% duty)
        let has_volume = outputs.contains(&8);
        let has_silence = outputs.contains(&0);
        assert!(has_volume && has_silence);
    }

    #[test]
    fn test_integration_length_counter_silences_channel() {
        let mut pulse = Pulse::default();

        // Setup with short length counter value
        pulse.write_control(0b1001_1111); // Duty 50%, no halt (bit 5 clear), constant volume=15
        pulse.write_timer_low(0x64);
        pulse.write_timer_high(0x00);
        pulse.set_length_counter_enabled(true);
        write_length(&mut pulse, 0b00000_000); // Load length=10 (index 0)

        // Initially should be able to output
        assert_eq!(pulse.get_length_counter(), 10);

        // Clock length counter 10 times to reach 0
        for _ in 0..10 {
            pulse.clock_length_counter();
        }

        assert_eq!(pulse.get_length_counter(), 0);
        assert_eq!(pulse.output(), 0); // Now silenced
    }

    #[test]
    fn test_integration_sweep_changes_period_over_time() {
        let mut pulse = Pulse::default();

        // Setup with sweep enabled
        pulse.write_control(0b1011_1111); // Duty 50%, constant volume=15
        pulse.write_timer_low(0x10); // Period = 16
        pulse.write_timer_high(0x00);
        write_length(&mut pulse, 0b00000_000); // Index 0 = 10
        pulse.write_sweep(0b1000_0001); // Enable, period=0, shift=1

        let initial_period = pulse.get_timer_period();
        assert_eq!(initial_period, 16);

        // First sweep clock reloads divider, no update yet
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 16);

        // Next sweep clocks should update
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 24);
        pulse.clock_sweep();
        assert_eq!(pulse.get_timer_period(), 36);
    }

    #[test]
    fn test_output_all_muting_conditions_independent() {
        let mut pulse = Pulse::default();

        // Start with valid setup
        pulse.write_control(0b1011_1111); // Duty 50%, constant volume=15
        pulse.write_timer_low(0x64); // Period = 100
        pulse.write_timer_high(0x00);
        write_length(&mut pulse, 0b00000_000); // Index 0 = 10

        // Test 1: Mute by clearing length counter
        pulse.set_length_counter_enabled(false);
        assert_eq!(pulse.output(), 0);

        // Restore length counter
        write_length(&mut pulse, 0b00000_000);

        // Test 2: Mute by setting period < 8
        pulse.write_timer_low(0x07);
        pulse.write_timer_high(0x00);
        assert_eq!(pulse.output(), 0);

        // Restore period
        pulse.write_timer_low(0x64);
        pulse.write_timer_high(0x00);

        // Test 3: Mute by sweep overflow
        write_length(&mut pulse, 0b00000_111); // Index 0, sets timer high to 7
        pulse.write_timer_low(0xFF); // Period = $7FF
        pulse.write_sweep(0b1000_0001); // Causes overflow
        assert_eq!(pulse.output(), 0);
    }

    #[test]
    fn reset_restores_pulse_to_initial_state_preserving_identity() {
        let mut pulse1 = Pulse::new(true);
        let mut pulse2 = Pulse::new(false);

        // Modify pulse1 state
        pulse1.write_control(0b1011_1111); // Duty 50%, constant volume=15
        pulse1.write_timer_low(0x64);
        pulse1.write_timer_high(0x03);
        pulse1.write_sweep(0b1000_0001);
        pulse1.set_length_counter_enabled(true);
        write_length(&mut pulse1, 0b00000_000);
        for _ in 0..100 {
            pulse1.clock_timer();
        }

        // Verify state changed
        assert!(pulse1.get_timer_period() > 0);
        assert!(pulse1.get_length_counter() > 0);

        // Reset both
        pulse1.reset();
        pulse2.reset();

        // Verify pulse1 reset to initial state
        assert_eq!(pulse1.get_timer_period(), 0);
        assert_eq!(pulse1.get_length_counter(), 0);
        assert_eq!(pulse1.output(), 0);

        // Verify identity preserved (is_pulse1 should still be true/false)
        // This is verified implicitly - if it weren't preserved, sweep would behave differently
        // We can test by setting up identical sweeps and checking they produce different results
        pulse1.write_timer_low(0x10);
        pulse1.write_timer_high(0x00);
        pulse1.write_sweep(0b1000_1001); // Enable, period=0, negate=1, shift=1
        pulse2.write_timer_low(0x10);
        pulse2.write_timer_high(0x00);
        pulse2.write_sweep(0b1000_1001); // Enable, period=0, negate=1, shift=1

        pulse1.clock_sweep();
        pulse2.clock_sweep();

        // First clock reloads divider, no update yet
        assert_eq!(pulse1.get_timer_period(), 16);
        assert_eq!(pulse2.get_timer_period(), 16);

        pulse1.clock_sweep();
        pulse2.clock_sweep();

        // Pulse1 uses ones' complement: 16 - (16>>1) - 1 = 16 - 8 - 1 = 7
        // Pulse2 uses two's complement: 16 - (16>>1) = 16 - 8 = 8
        assert_eq!(pulse1.get_timer_period(), 7);
        assert_eq!(pulse2.get_timer_period(), 8);
    }
}
