use crossterm::event::{KeyCode, KeyEvent};
use std::sync::atomic::Ordering;

use super::{InputContext, InputResult};
use crate::commands::AppCommand;
use crate::engine::{AudioCommand, SeqCommand};
use crate::state::{ConfirmAction, DeviceKind, EngineSection, Modal, SettingKind};

pub(crate) fn cycle_engine_setting(ctx: &mut InputContext, right: bool) {
    let sign = if right { 1 } else { -1 };
    match ctx.app.audio.setting_kind {
        SettingKind::Channels => ctx.dispatch(AppCommand::AdjustAudioSetting {
            setting: SettingKind::Channels,
            delta: sign,
        }),
        SettingKind::BufferSize => ctx.dispatch(AppCommand::AdjustAudioSetting {
            setting: SettingKind::BufferSize,
            delta: sign * 64,
        }),
        SettingKind::Polyphony => ctx.dispatch(AppCommand::AdjustAudioSetting {
            setting: SettingKind::Polyphony,
            delta: sign,
        }),
        SettingKind::Nudge => {
            let prev = ctx.nudge_us.load(Ordering::Relaxed);
            let new_val = prev + sign as i64 * 1000;
            ctx.nudge_us
                .store(new_val.clamp(-100_000, 100_000), Ordering::Relaxed);
        }
    }
    ctx.app.save_settings(ctx.link);
}

pub(super) fn handle_engine_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
    match key.code {
        KeyCode::Char('q') if !ctx.app.plugin_mode => {
            ctx.dispatch(AppCommand::OpenModal(Modal::Confirm {
                action: ConfirmAction::Quit,
                selected: false,
            }));
        }
        KeyCode::Tab => ctx.dispatch(AppCommand::AudioNextSection),
        KeyCode::BackTab => ctx.dispatch(AppCommand::AudioPrevSection),
        KeyCode::Up => match ctx.app.audio.section {
            EngineSection::Devices if !ctx.app.plugin_mode => match ctx.app.audio.device_kind {
                DeviceKind::Output => ctx.dispatch(AppCommand::AudioOutputListUp),
                DeviceKind::Input => ctx.dispatch(AppCommand::AudioInputListUp),
            },
            EngineSection::Settings => {
                ctx.dispatch(AppCommand::AudioSettingPrev);
            }
            EngineSection::Samples => {
                ctx.app.audio.sample_list.move_up();
            }
            _ => {}
        },
        KeyCode::Down => match ctx.app.audio.section {
            EngineSection::Devices if !ctx.app.plugin_mode => match ctx.app.audio.device_kind {
                DeviceKind::Output => {
                    let count = ctx.app.audio.output_devices.len();
                    ctx.dispatch(AppCommand::AudioOutputListDown(count));
                }
                DeviceKind::Input => {
                    let count = ctx.app.audio.input_devices.len();
                    ctx.dispatch(AppCommand::AudioInputListDown(count));
                }
            },
            EngineSection::Settings => {
                ctx.dispatch(AppCommand::AudioSettingNext);
            }
            EngineSection::Samples => {
                let count = ctx.app.audio.config.sample_paths.len();
                ctx.app.audio.sample_list.move_down(count);
            }
            _ => {}
        },
        KeyCode::PageUp => {
            if !ctx.app.plugin_mode && ctx.app.audio.section == EngineSection::Devices {
                match ctx.app.audio.device_kind {
                    DeviceKind::Output => ctx.dispatch(AppCommand::AudioOutputPageUp),
                    DeviceKind::Input => ctx.app.audio.input_list.page_up(),
                }
            }
        }
        KeyCode::PageDown => {
            if !ctx.app.plugin_mode && ctx.app.audio.section == EngineSection::Devices {
                match ctx.app.audio.device_kind {
                    DeviceKind::Output => {
                        let count = ctx.app.audio.output_devices.len();
                        ctx.dispatch(AppCommand::AudioOutputPageDown(count));
                    }
                    DeviceKind::Input => {
                        let count = ctx.app.audio.input_devices.len();
                        ctx.dispatch(AppCommand::AudioInputPageDown(count));
                    }
                }
            }
        }
        KeyCode::Enter => {
            if !ctx.app.plugin_mode && ctx.app.audio.section == EngineSection::Devices {
                match ctx.app.audio.device_kind {
                    DeviceKind::Output => {
                        let cursor = ctx.app.audio.output_list.cursor;
                        if cursor < ctx.app.audio.output_devices.len() {
                            let name = ctx.app.audio.output_devices[cursor].name.clone();
                            ctx.dispatch(AppCommand::SetOutputDevice(name));
                            ctx.app.save_settings(ctx.link);
                        }
                    }
                    DeviceKind::Input => {
                        let cursor = ctx.app.audio.input_list.cursor;
                        if cursor < ctx.app.audio.input_devices.len() {
                            let name = ctx.app.audio.input_devices[cursor].name.clone();
                            ctx.dispatch(AppCommand::SetInputDevice(name));
                            ctx.app.save_settings(ctx.link);
                        }
                    }
                }
            }
        }
        KeyCode::Left => match ctx.app.audio.section {
            EngineSection::Devices if !ctx.app.plugin_mode => {
                ctx.dispatch(AppCommand::SetDeviceKind(DeviceKind::Output));
            }
            EngineSection::Settings => cycle_engine_setting(ctx, false),
            _ => {}
        },
        KeyCode::Right => match ctx.app.audio.section {
            EngineSection::Devices if !ctx.app.plugin_mode => {
                ctx.dispatch(AppCommand::SetDeviceKind(DeviceKind::Input));
            }
            EngineSection::Settings => cycle_engine_setting(ctx, true),
            _ => {}
        },
        KeyCode::Char('R') if !ctx.app.plugin_mode => {
            ctx.dispatch(AppCommand::AudioTriggerRestart);
        }
        KeyCode::Char('A') if ctx.app.audio.section == EngineSection::Samples => {
            use crate::state::file_browser::FileBrowserState;
            let state = FileBrowserState::new_load(String::new());
            ctx.dispatch(AppCommand::OpenModal(Modal::AddSamplePath(Box::new(state))));
        }
        KeyCode::Char('D') => {
            if ctx.app.audio.section == EngineSection::Samples {
                let cursor = ctx.app.audio.sample_list.cursor;
                ctx.dispatch(AppCommand::RemoveSamplePath(cursor));
                ctx.app.save_settings(ctx.link);
            } else if !ctx.app.plugin_mode {
                ctx.dispatch(AppCommand::AudioRefreshDevices);
                let out_count = ctx.app.audio.output_devices.len();
                let in_count = ctx.app.audio.input_devices.len();
                ctx.dispatch(AppCommand::SetStatus(format!(
                    "Found {out_count} output, {in_count} input devices"
                )));
            }
        }
        KeyCode::Char('h') => {
            if !ctx.app.plugin_mode {
                let _ = ctx.audio_tx.load().send(AudioCommand::Hush);
            }
            let _ = ctx.seq_cmd_tx.send(SeqCommand::StopAll);
        }
        KeyCode::Char('p') => {
            if !ctx.app.plugin_mode {
                let _ = ctx.audio_tx.load().send(AudioCommand::Panic);
            }
            let _ = ctx.seq_cmd_tx.send(SeqCommand::StopAll);
        }
        KeyCode::Char('r') => ctx.dispatch(AppCommand::ResetPeakVoices),
        KeyCode::Char('t') if !ctx.app.plugin_mode => {
            let _ = ctx.audio_tx.load().send(AudioCommand::Evaluate {
                cmd: "/sound/sine/dur/0.5/decay/0.2".into(),
                time: None,
            });
        }
        KeyCode::Char('s') => super::open_save(ctx),
        KeyCode::Char('l') => super::open_load(ctx),
        KeyCode::Char('?') => {
            ctx.dispatch(AppCommand::OpenModal(Modal::KeybindingsHelp { scroll: 0 }));
        }
        KeyCode::Char(' ') if !ctx.app.plugin_mode => {
            ctx.dispatch(AppCommand::TogglePlaying);
            ctx.playing
                .store(ctx.app.playback.playing, Ordering::Relaxed);
        }
        _ => {}
    }
    InputResult::Continue
}
