use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::time::Duration;
use clap::Parser;

// Framing tags
const TAG_CONTROL_OUT: u8 = 0x10;
const TAG_CONTROL_IN: u8 = 0x11;
const TAG_BULK: u8 = 0x20;

const ADSB_MESSAGE: [u8; 14] = [
  0x8D, 0x48, 0x40, 0xD6, 0x20, 0x2C, 0xC3,
  0x71, 0xC3, 0x2C, 0xE0, 0x57, 0x60, 0x98,
];

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct SimulationArgs {
  /// Host/IP to bind the TCP listener on
  #[arg(long, default_value = "127.0.0.1")]
  host: String,

  /// TCP port to bind the listener on
  #[arg(long, default_value = "9999")]
  port: u16,
}

fn main() {
  // Parse command‐line arguments
  let args = SimulationArgs::parse();

  // Build the bind address, e.g. "127.0.0.1:9999"
  let bind_address = format!("{}:{}", args.host, args.port);
  println!("Listening on {}", bind_address);

  // Start listening for incoming TCP connections
  let listener = TcpListener::bind(&bind_address)
    .unwrap_or_else(|err| panic!("failed to bind {}: {}", bind_address, err));

  // Accept connections in a loop
  for incoming in listener.incoming() {
    match incoming {
      Ok(client_stream) => {
        // Spawn a thread per client
        thread::spawn(move || handle_client_connection(client_stream));
      }
      Err(err) => eprintln!("Error accepting connection: {}", err),
    }
  }
}

/// Handle a single client connection
fn handle_client_connection(mut connection: TcpStream) {
  // Track a "current frequency"
  let mut current_frequency_hz: u32 = 0;

  loop {
    // Read the 4-byte header: [tag:1][bRequest:1][length:2]
    let mut header_buffer = [0u8; 4];
    if connection.read_exact(&mut header_buffer).is_err() {
      // Client closed on error
      break;
    }

    let message_tag = header_buffer[0];
    let b_request = header_buffer[1];
    let payload_length = u16::from_le_bytes([header_buffer[2], header_buffer[3]]) as usize;

    // Read the optional payload
    let mut payload_buffer = vec![0u8; payload_length];
    if payload_length > 0 {
      if connection.read_exact(&mut payload_buffer).is_err() {
        break;
      }
    }

    // Dispatch based on the framing tag
    match message_tag {
      TAG_CONTROL_OUT => {
        // Simulate accepting a CONTROL_OUT (e.g. SET_FREQ)
        if b_request == 0x02 && payload_buffer.len() == 4 {
          current_frequency_hz = u32::from_le_bytes([
            payload_buffer[0],
            payload_buffer[1],
            payload_buffer[2],
            payload_buffer[3]
          ]);
          println!("SET_FREQ -> {} Hz", current_frequency_hz);
        }
        // Acknowledge with a single byte = 0 (OK)
        connection.write_all(&[0u8]).ok();
      },
      TAG_CONTROL_IN => {
        dbg!(message_tag);
        // Simulate a CONTROL_IN reply with a fixed pattern

        // Status byte
        let _ = connection.write_all(&[0u8]);

        // 2-byte little-endian length
        let length_u16 = payload_length as u16;
        let _ = connection.write_all(&length_u16.to_le_bytes());

        // Payload (0x42 repeated)
        let reply = vec![0x42; payload_length];
        let _ = connection.write_all(&reply).ok();
      },
      TAG_BULK => {
        dbg!(message_tag);
        // Generate a ADS-B IQ burst
        let iq_samples = generate_adsb_iq_samples();
        let length_u32 = (iq_samples.len() as u32).to_le_bytes();

        // Send status byte = 0 (OK)
        let _ = connection.write_all(&[0u8]);

        // Send 4-byte little-endian length (bulk uses u32)
        let _ = connection.write_all(&length_u32);

        // Send the IQ payload
        let _ = connection.write_all(&iq_samples);

        // Throttle a bit to simulate real USB/bulk behavior
        thread::sleep(Duration::from_millis(10));
      },
      _unknown_tag => {
        // On any unrecognized tag, break out
        break
      },
    }
  }

  println!("Connection closed");
}

/// Build one preamble (8 bits) + 112 data bits
/// Sampled at 2 Mhz (1 sample per half-bit). Interleaved I/Q bytes
fn generate_adsb_iq_samples() -> Vec<u8> {
  // Preamble bits (1us per bit at 2 Mhz -> 2 samples per bit)
  // Preamble is 8 bits: 1,0,1,0,1,0,0,0
  let preamble_bits = [1, 0, 1, 0, 1, 0, 0, 0];

  // Manchester encode the 112 data bits
  // bit=0 -> [1,0], bit=1 -> [0,1] (half-bit intervals)
  let mut manchester_bits = Vec::with_capacity(112 * 2);
  for &byte in ADSB_MESSAGE.iter() {
    for bit_idx in (0..8).rev() {
      let bit = (byte >> bit_idx) & 1;
      if bit == 0 {
        manchester_bits.push(1);
        manchester_bits.push(0);
      } else {
        manchester_bits.push(0);
        manchester_bits.push(1);
      }
    }
  }

  // Concatenate preamble + data
  let mut full_bitstream = Vec::with_capacity(
    preamble_bits.len() * 2 + manchester_bits.len());

  // Preamble: each '1' or '0' is one microsecond = 2 samples
  for &pb in preamble_bits.iter() {
    // Push two identical half-bits = 2 samples
    full_bitstream.push(pb);
    full_bitstream.push(pb);
  }

  // Data: already in half-bit units = 1 sample per element
  full_bitstream.extend(manchester_bits);

  // Build interleaved I/Q samples
  // I = 128 + 127*(bit), Q = 128
  let mut iq = Vec::with_capacity(full_bitstream.len() * 2);
  for &level in full_bitstream.iter() {
    let i_sample = if level == 1 {
      255u8
    } else {
      128u8
    };
    let q_sample = 128u8;
    iq.push(i_sample);
    iq.push(q_sample);
  }

  iq
}
