//! Client Node entry point.
//!
//! This module initializes the desktop client application, sets up the Tokio
//! background thread for networking, and eventually binds to the UI framework.

#![forbid(unsafe_code)]
#![deny(clippy::all, clippy::pedantic)]
#![deny(clippy::unwrap_used, clippy::expect_used)]

mod audio;
mod hotkey;
mod network;
mod ui;

use anyhow::Result;
use eframe::egui;
use ringbuf::HeapRb;
use ringbuf::traits::Split;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use tokio::sync::watch;
use tracing::{error, info};

fn main() -> Result<()> {
    tracing_subscriber::fmt::init();
    info!("Starting client node...");

    // ── Communication channels ──
    let (active_speaker_tx, active_speaker_rx) = watch::channel(false);
    let (mic_level_tx, mic_level_rx) = watch::channel(0.0_f32);
    let ptt_flag = Arc::new(AtomicBool::new(false));
    let mute_flag = Arc::new(AtomicBool::new(false));
    let audio_dumper_flag = Arc::new(AtomicBool::new(false));
    let loopback_flag = Arc::new(AtomicBool::new(false));

    // ── Lock-free ringbuffer for audio capture (4096 capacity) ──
    let audio_rb = HeapRb::<f32>::new(4096);
    let (producer, consumer) = audio_rb.split();

    // ── Lock-free ringbuffer for audio loopback (4096 capacity) ──
    let loopback_rb = HeapRb::<f32>::new(4096);
    let (loopback_prod, loopback_cons) = loopback_rb.split();

    // ── Spawn DSP and audio capture threads ──
    audio::dsp::spawn_dsp_thread(
        consumer,
        loopback_prod,
        ptt_flag.clone(),
        mute_flag.clone(),
        audio_dumper_flag.clone(),
        active_speaker_tx,
        mic_level_tx,
    );
    let _stream = audio::capture::start_audio_capture(producer).map_err(|e| {
        error!("Failed to start audio capture: {:?}", e);
        e
    });

    // ── Spawn playback/loopback stream ──
    let _playback_stream = audio::playback::start_audio_playback(loopback_cons, loopback_flag.clone()).map_err(|e| {
        error!("Failed to start audio playback: {:?}", e);
        e
    });

    // ── Spawn Global Hotkey listener ──
    hotkey::spawn_hotkey_listener(ptt_flag.clone());

    // ── Spawn custom tokio runtime for network background tasks ──
    std::thread::spawn(move || {
        let Ok(rt) = tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
        else {
            tracing::error!("Failed to build tokio runtime");
            return;
        };

        rt.block_on(async {
            if let Err(e) = network::control::connect_and_auth("TestUser").await {
                error!("Connection error: {:?}", e);
            }
        });
    });

    let options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default()
            .with_inner_size([960.0, 640.0])
            .with_min_inner_size([640.0, 400.0]),
        renderer: eframe::Renderer::Glow,
        ..Default::default()
    };

    eframe::run_native(
        "Voice App",
        options,
        Box::new(|cc| {
            Ok(Box::new(ui::VoiceApp::new(
                cc,
                mic_level_rx,
                mute_flag,
                audio_dumper_flag,
            )))
        }),
    )
    .map_err(|e| anyhow::anyhow!("eframe error: {e:?}"))?;

    Ok(())
}
