use qrcodegen::{ QrCode, QrCodeEcc };

/// Returns the device's primary local IP address, or 127.0.0.1 as fallback.
pub fn local_ip() -> String
{
	use std::net::UdpSocket;
	let socket = UdpSocket::bind( "0.0.0.0:0" ).ok()
		.and_then( |s| { s.connect( "8.8.8.8:80" ).ok().map( |_| s ) } );
	if let Some( s ) = socket
	{
		if let Ok( addr ) = s.local_addr()
		{
			return addr.ip().to_string();
		}
	}
	"127.0.0.1".to_string()
}

/// Renders a QR code for `text` into an RGBA pixel buffer of `pixel_size × pixel_size`.
pub fn generate_qr_rgba( text: &str, pixel_size: u32 ) -> ( Vec<u8>, u32, u32 )
{
	let qr      = QrCode::encode_text( text, QrCodeEcc::Medium ).expect( "QR encode" );
	let modules = qr.size() as u32;
	let border  = pixel_size / 16;
	let inner   = pixel_size - 2 * border;
	let scale   = inner / modules;
	let used    = scale * modules;
	let offset  = border + ( inner - used ) / 2;

	// White RGBA background
	let mut pixels = vec![ 255u8; ( pixel_size * pixel_size * 4 ) as usize ];

	for row in 0..modules
	{
		for col in 0..modules
		{
			if qr.get_module( col as i32, row as i32 )
			{
				for dy in 0..scale
				{
					for dx in 0..scale
					{
						let px = ( offset + row * scale + dy ) * pixel_size
							+ ( offset + col * scale + dx );
						let i       = ( px * 4 ) as usize;
						pixels[i]     = 0;
						pixels[i + 1] = 0;
						pixels[i + 2] = 0;
						pixels[i + 3] = 255;
					}
				}
			}
		}
	}

	( pixels, pixel_size, pixel_size )
}

fn handle_request( path: &str, _method: &str ) -> ( &'static str, String )
{
	match path
	{
		"/api/v1/status" =>
		{
			let body = r#"{"service":"SmartCast REST API","status":"ok","version":"1.0"}"#;
			( "200 OK", body.to_string() )
		}
		_ =>
		{
			( "404 Not Found", r#"{"error":"Not found"}"#.to_string() )
		}
	}
}

/// Starts the SmartCast REST server on the given port in a background thread.
pub fn start_server( port: u16 )
{
	std::thread::spawn( move ||
	{
		use std::net::TcpListener;
		use std::io::{ BufRead, BufReader, Write };

		let listener = TcpListener::bind( format!( "0.0.0.0:{}", port ) )
			.expect( "SmartCast server bind" );
		tracing::info!( "SmartCast REST server listening on :{}", port );

		for stream in listener.incoming()
		{
			if let Ok( mut stream ) = stream
			{
				let mut reader       = BufReader::new( &stream );
				let mut request_line = String::new();
				let _ = reader.read_line( &mut request_line );

				// Drain remaining HTTP headers
				let mut line = String::new();
				loop
				{
					line.clear();
					if reader.read_line( &mut line ).unwrap_or( 0 ) == 0 { break; }
					if line == "\r\n" || line == "\n" { break; }
				}

				let parts  = request_line.split_whitespace().collect::<Vec<_>>();
				let path   = parts.get( 1 ).copied().unwrap_or( "/" );
				let method = parts.get( 0 ).copied().unwrap_or( "GET" );

				let ( status, body ) = handle_request( path, method );
				let response = format!(
					"HTTP/1.1 {}\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
					status, body.len(), body
				);
				let _ = stream.write_all( response.as_bytes() );
			}
		}
	} );
}
