
use rmk::config::{BehaviorConfig, ForksConfig, PositionalConfig};
use rmk::fork::{Fork, StateBits};
use rmk::types::action::{Action, KeyAction};
use rmk::types::modifier::ModifierCombination;
use rmk::{a, heapless, k, layer};

use crate::vial::CustomKeycodes;

pub const NUM_LAYER: usize = 8;
pub const MATRIX_ROWS: usize = 5;
pub const MATRIX_COLS: usize = 12;
pub const MATRIX_AREA: usize = MATRIX_ROWS * MATRIX_COLS;

const T: KeyAction = a!(Transparent);

#[rustfmt::skip]
pub const fn get_default_keymap() -> [[[KeyAction; MATRIX_COLS]; MATRIX_ROWS]; NUM_LAYER] {
    [
        layer!([
            [k!(Escape), k!(Kc1), k!(Kc2), k!(Kc3), k!(Kc4), k!(Kc5), k!(Kc6), k!(Kc7), k!(Kc8), k!(Kc9), k!(Kc0), k!(Backspace)],
            [k!(Tab), k!(Q), k!(W), k!(E), k!(R), k!(T), k!(Z), k!(U), k!(I), k!(O), k!(P), k!(Delete)],
            [k!(LCtrl), k!(A), k!(S), k!(D), k!(F), k!(G), k!(H), k!(J), k!(K), k!(L), k!(Comma), k!(Enter)],
            [k!(LShift), k!(Y), k!(X), k!(C), k!(V), k!(B), k!(N), k!(M), a!(No), a!(No), k!(Up), KeyAction::Single(Action::User(CustomKeycodes::FOCUS_LCD as u8))],
            [a!(No), a!(No), k!(LGui), k!(LAlt), KeyAction::Single(Action::TriLayerLower), k!(Space), k!(Space), KeyAction::Single(Action::TriLayerLower), k!(RAlt), k!(Left), k!(Down), k!(Right)]
            // [a!(No), a!(No), k!(LGui), k!(LAlt), k!(TriLayerLower), k!(Space), k!(Space), k!(TriLayerLower), k!(RAlt), k!(Left), k!(Down), k!(Right)]
        ]),
        layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]),
        layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]),
        layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]),
        layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]),
        layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]),
        layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]),
        layer!([[T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T], [T, T, T, T, T, T, T, T, T, T, T, T]]),
    ]
}

fn fork_by_shift(
    trigger: CustomKeycodes,
    negative_output: KeyAction,
    positive_output: KeyAction,
    keep_shift: bool,
) -> Fork {
    Fork::new(
        KeyAction::Single(Action::User(trigger as u8)),
        negative_output,
        positive_output,
        StateBits::new_from(
            ModifierCombination::new()
                .with_left_shift(true)
                .with_right_shift(true),
            Default::default(),
            Default::default(),
        ),
        StateBits::default(),
        ModifierCombination::new()
            .with_left_shift(keep_shift)
            .with_right_shift(keep_shift),
        false,
    )
}

pub fn get_behavior_config() -> BehaviorConfig {
    BehaviorConfig {
        fork: ForksConfig {
            forks: {
                let mut forks = heapless::Vec::new();
                forks
                    .push(fork_by_shift(
                        CustomKeycodes::FORK_ACUTE_ABOVERING_CS,
                        rmk::k!(Equal),
                        rmk::k!(Grave), // Shift is kept
                        true,
                    ))
                    .unwrap();
                forks
                    .push(fork_by_shift(
                        CustomKeycodes::FORK_CARON_DIAERESIS_CS,
                        rmk::shifted!(Equal),
                        rmk::wm!(Minus, ModifierCombination::new().with_right_alt(true)),
                        false,
                    ))
                    .unwrap();
                forks
                    .push(fork_by_shift(
                        CustomKeycodes::FORK_ACUTE_ABOVERING_CSP,
                        rmk::wm!(Equal, ModifierCombination::new().with_right_alt(true)),
                        rmk::wm!(Grave, ModifierCombination::new().with_right_alt(true)), // Shift is kept
                        true,
                    ))
                    .unwrap();
                forks
                    .push(fork_by_shift(
                        CustomKeycodes::FORK_CARON_DIAERESIS_CSP,
                        rmk::wm!(
                            Equal,
                            ModifierCombination::new()
                                .with_left_shift(true)
                                .with_right_alt(true)
                        ),
                        rmk::wm!(Backslash, ModifierCombination::new().with_right_alt(true)),
                        false,
                    ))
                    .unwrap();
                forks
                    .push(fork_by_shift(
                        CustomKeycodes::FORK_9_FORWARDSLASH_EN_CSP,
                        rmk::k!(Kc9),
                        rmk::k!(Slash),
                        false,
                    ))
                    .unwrap();
                forks
                    .push(fork_by_shift(
                        CustomKeycodes::FORK_0_BACKWARDSLASH_EN_CSP,
                        rmk::k!(Kc0),
                        rmk::k!(Backslash),
                        false,
                    ))
                    .unwrap();
                forks
            },
        },
        ..Default::default()
    }
}

pub fn get_positional_config() -> PositionalConfig<MATRIX_ROWS, MATRIX_COLS> {
    PositionalConfig::default()
}
