mod args;
mod interpolation;
mod osc_client;
mod pendulum;
mod ui;

use anyhow::anyhow;
use anyhow::Result;

const COLUMNS: usize = 5;
const ROWS: usize = 5;

trait DisplayStr {
    fn display_str(&self) -> &'static str;
}

impl DisplayStr for osc::TrackState {
    fn display_str(&self) -> &'static str {
        match self {
            osc::TrackState::Empty => "---",
            osc::TrackState::Idle => "READY",
            osc::TrackState::Recording => "REC",
            osc::TrackState::Playing => "PLAY",
        }
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Parse arguments
    let args = args::Args::new()?;

    // Configuration
    let socket_path = "fcb_looper.sock";

    // Logger
    simple_logger::SimpleLogger::new()
        .with_level(log::LevelFilter::Info)
        .with_module_level("gui::osc_client", log::LevelFilter::Off)
        .with_module_level("osc", log::LevelFilter::Debug)
        .init()
        .expect("Could not initialize logger");

    // Create OSC client
    let osc_client = osc_client::Client::<COLUMNS, ROWS>::new(socket_path)?;
    let state_receiver = osc_client.state_receiver();

    // Spawn OSC receiver thread on tokio runtime
    tokio::spawn(async move {
        if let Err(e) = osc_client.run().await {
            eprintln!("OSC client error: {}", e);
        }
    });

    // Run egui on main thread
    let mut viewport_builder = egui::ViewportBuilder::default()
        .with_inner_size([800.0, 600.0])
        .with_min_inner_size([50.0, 50.0]);
    
    if args.full_screen {
        viewport_builder = viewport_builder.with_fullscreen(true);
    }

    let options = eframe::NativeOptions {
        viewport: viewport_builder,
        ..Default::default()
    };

    // This blocks the main thread with egui's event loop
    eframe::run_native(
        "FCB Looper",
        options,
        Box::new(|_cc| Ok(Box::new(ui::App::<COLUMNS, ROWS>::new(state_receiver)))),
    )
    .map_err(|e| anyhow::anyhow!("Failed to run egui: {}", e))?;

    Ok(())
}
