use tinyvec::ArrayVec;

use crate::peripherals::st7701s::commands::*;

pub enum InitSequenceAction {
    // TODO: Each command takes up 17 bytes. Consider storing compressed.
    Command(ArrayCommand<16>),
    SleepMs(u64),
}

macro_rules! make_init_action {
    (command: $command:expr$(,)?) => {
        InitSequenceAction::Command({
            let command = $command;
            let args_slice = command.args_slice();
            let mut args_array = [0; _];
            let mut args_len = 0;
            while args_len < args_slice.len() {
                args_array[args_len] = args_slice[args_len];
                args_len += 1;
            }
            ArrayCommand {
                address: command.address_const(),
                args: match ArrayVec::try_from_array_len(args_array, args_len) {
                    Ok(args) => args,
                    Err(_) => panic!("too many command args"),
                },
            }
        })
    };

    (sleep_ms: $expr:expr) => {
        InitSequenceAction::SleepMs($expr)
    };
}

macro_rules! make_init_sequence {
    ($({ $($tt:tt)* }),*$(,)?) => {
        [
            $( make_init_action!($($tt)*) ),*
        ]
    };
}

pub const INIT_SEQUENCE_COMMANDS: [InitSequenceAction; 46] = make_init_sequence! [
    { command: CmdCn2bkxsel(
        CmdCn2bkxselArg0::new(),
        CmdCn2bkxselArg1::new(),
        CmdCn2bkxselArg2::new(),
        CmdCn2bkxselArg3::new(),
        CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
    ) },
    { command: CustomCommand {
        address: 0xEF,
        args: &[0x08],
    } },
    { command: CmdCn2bkxsel(
        CmdCn2bkxselArg0::new(),
        CmdCn2bkxselArg1::new(),
        CmdCn2bkxselArg2::new(),
        CmdCn2bkxselArg3::new(),
        CmdCn2bkxselArg4::new().with_bksel(0x0).with_cn2(true),
    ) },
    { command: CmdLneset(
        CmdLnesetArg0::new().with_bar(119).with_lde_en(false),
        CmdLnesetArg1::new().with_line_delta(0),
    ) },
    { command: CmdPorctrl(
        CmdPorctrlArg0::new().with_vbp(17),
        CmdPorctrlArg1::new().with_vfp(12),
    ) },
    { command: CmdInvsel(
        CmdInvselArg0::new().with_nlinv(0b111),
        CmdInvselArg1::new().with_rtni(2),
    ) },
    { command: CustomCommand {
        address: 0xCC,
        args: &[0x30],
    } },
    { command: CmdPvgamctrl(
        CmdPvgamctrlArg0::new().with_vc0p(6).with_aj0p(0),
        CmdPvgamctrlArg1::new().with_vc4p(15).with_aj1p(3),
        CmdPvgamctrlArg2::new().with_vc8p(14).with_aj2p(0),
        CmdPvgamctrlArg3::new().with_vc16p(12),
        CmdPvgamctrlArg4::new().with_vc24p(15).with_aj3p(0),
        CmdPvgamctrlArg5::new().with_vc52p(3),
        CmdPvgamctrlArg6::new().with_vc80p(0),
        CmdPvgamctrlArg7::new().with_vc108p(10),
        CmdPvgamctrlArg8::new().with_vc147p(7),
        CmdPvgamctrlArg9::new().with_vc175p(27),
        CmdPvgamctrlArg10::new().with_vc203p(3),
        CmdPvgamctrlArg11::new().with_vc231p(18).with_aj4p(0),
        CmdPvgamctrlArg12::new().with_vc239p(16),
        CmdPvgamctrlArg13::new().with_vc247p(37).with_aj5p(0),
        CmdPvgamctrlArg14::new().with_vc251p(54).with_aj6p(0),
        CmdPvgamctrlArg15::new().with_vc255p(30).with_aj7p(0),
    ) },
    { command: CmdNvgamctrl(
        CmdNvgamctrlArg0::new().with_vc0n(12).with_aj0n(0),
        CmdNvgamctrlArg1::new().with_vc4n(14).with_aj1n(3),
        CmdNvgamctrlArg2::new().with_vc8n(18).with_aj2n(0),
        CmdNvgamctrlArg3::new().with_vc16n(12),
        CmdNvgamctrlArg4::new().with_vc24n(14).with_aj3n(0),
        CmdNvgamctrlArg5::new().with_vc52n(6),
        CmdNvgamctrlArg6::new().with_vc80n(3),
        CmdNvgamctrlArg7::new().with_vc108n(6),
        CmdNvgamctrlArg8::new().with_vc147n(8),
        CmdNvgamctrlArg9::new().with_vc175n(35),
        CmdNvgamctrlArg10::new().with_vc203n(6),
        CmdNvgamctrlArg11::new().with_vc231n(18).with_aj4n(0),
        CmdNvgamctrlArg12::new().with_vc239n(16),
        CmdNvgamctrlArg13::new().with_vc247n(48).with_aj5n(0),
        CmdNvgamctrlArg14::new().with_vc251n(47).with_aj6n(0),
        CmdNvgamctrlArg15::new().with_vc255n(31).with_aj7n(0),
    ) },
    { command: CmdCn2bkxsel(
        CmdCn2bkxselArg0::new(),
        CmdCn2bkxselArg1::new(),
        CmdCn2bkxselArg2::new(),
        CmdCn2bkxselArg3::new(),
        CmdCn2bkxselArg4::new().with_bksel(0x1).with_cn2(true),
    ) },
    { command: CmdVrhs(
        CmdVrhsArg0::new().with_vrha(115),
    ) },
    { command: CmdVcoms(
        CmdVcomsArg0::new().with_vcom(124),
    ) },
    { command: CmdVghss(
        // The first bit is set to 1 in the original init code, but not here.
        CmdVghssArg0::new().with_vghss(0x3), // 13 V
    ) },
    { command: CmdTescmd(
        CmdTescmdArg0::new(),
    ) },
    { command: CmdVgls(
        CmdVglsArg0::new().with_vgls(0x9) // -10.17 V
    ) },
    { command: CmdPwctrl1(
        CmdPwctrl1Arg0::new()
        .with_apos(0x3) // Max
        .with_apis(0x1) // Min
        .with_ap(0x2) // Middle
    ) },
    { command: CmdPwctrl2(
        CmdPwctrl2Arg0::new()
            .with_avcl(0x3) // -5 V
            .with_avdd(0x3) // 6.8 V
    ) },
    { command: CmdPwctrl3(
        CmdPwctrl3Arg0::new()
        .with_svno_pum(0) // Cell setting 4
        .with_svpo_pum(0x1)  // Cell setting 5
    ) },
    { command: CmdPclks2(
        CmdPclks2Arg0::new().with_sbstcks(0x3)
    ) },
    { command: CmdPdr1(
        CmdPdr1Arg0::new().with_t2d(8) // 1.6 us
    ) },
    { command: CmdPdr2(
        CmdPdr2Arg0::new().with_t3d(8) // 6.4 us
    ) },
    { command: CmdMipiset1(
        CmdMipiset1Arg0::new().with_err_sel(0).with_eotp_en(true),
    ) },
    { command: CustomCommand {
        address: 0xE0,
        args: &[
            0x00,
            0x00,
            0x02,
            0x00,
            0x00,
            0x0C,
        ]
    } },
    { command: CustomCommand {
        address: 0xE1,
        args: &[
            0x05,
            0x96,
            0x07,
            0x96,
            0x06,
            0x96,
            0x08,
            0x96,
            0x00,
            0x44,
            0x44,
        ]
    } },
    { command: CustomCommand {
        address: 0xE2,
        args: &[
            0x00,
            0x00,
            0x03,
            0x03,
            0x00,
            0x00,
            0x02,
            0x00,
            0x00,
            0x00,
            0x02,
            0x00,
        ]
    } },
    { command: CustomCommand {
        address: 0xE3,
        args: &[
            0x00,
            0x00,
            0x33,
            0x33,
        ]
    } },
    { command: CustomCommand {
        address: 0xE4,
        args: &[
            0x44,
            0x44,
        ]
    } },
    { command: CustomCommand {
        address: 0xE5,
        args: &[
            0x0D,
            0xD4,
            0x28,
            0x8C,
            0x0F,
            0xD6,
            0x28,
            0x8C,
            0x09,
            0xD0,
            0x28,
            0x8C,
            0x0B,
            0xD2,
            0x28,
            0x8C,
        ]
    } },
    { command: CustomCommand {
        address: 0xE6,
        args: &[
            0x00,
            0x00,
            0x33,
            0x33,
        ]
    } },
    { command: CustomCommand {
        address: 0xE7,
        args: &[
            0x44,
            0x44,
        ]
    } },
    { command: CustomCommand {
        address: 0xE8,
        args: &[
            0x0E,
            0xD5,
            0x28,
            0x8C,
            0x10,
            0xD7,
            0x28,
            0x8C,
            0x0A,
            0xD1,
            0x28,
            0x8C,
            0x0C,
            0xD3,
            0x28,
            0x8C,
        ]
    } },
    { command: CustomCommand {
        address: 0xEB,
        args: &[
            0x00,
            0x01,
            0xE4,
            0xE4,
            0x44,
            0x00,
        ]
    } },
    { command: CustomCommand {
        address: 0xED,
        args: &[
            0xF3,
            0xC1,
            0xBA,
            0x0F,
            0x66,
            0x77,
            0x44,
            0x55,
            0x55,
            0x44,
            0x77,
            0x66,
            0xF0,
            0xAB,
            0x1C,
            0x3F,
        ]
    } },
    { command: CustomCommand {
        address: 0xEF,
        args: &[
            0x10,
            0x0D,
            0x04,
            0x08,
            0x3F,
            0x1F,
        ]
    } },
    { command: CmdCn2bkxsel(
        CmdCn2bkxselArg0::new(),
        CmdCn2bkxselArg1::new(),
        CmdCn2bkxselArg2::new(),
        CmdCn2bkxselArg3::new(),
        CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
    ) },
    { command: CustomCommand {
        address: 0xE8,
        args: &[
            0x00,
            0x0E,
        ],
    } },
    { command: CmdSlpout() },
    { sleep_ms: 120 },
    { command: CustomCommand {
        address: 0xE8,
        args: &[
            0x00,
            0x0C,
        ],
    } },
    { sleep_ms: 10 },
    { command: CustomCommand {
        address: 0xE8,
        args: &[
            0x40,
            0x00,
        ],
    } },
    { command: CmdCn2bkxsel(
        CmdCn2bkxselArg0::new(),
        CmdCn2bkxselArg1::new(),
        CmdCn2bkxselArg2::new(),
        CmdCn2bkxselArg3::new(),
        CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
    ) },
    { command: CmdMadctl(
        CmdMadctlArg0::new().with_bgr(false).with_ml(false),
    ) },
    { command: CmdColmod(
        CmdColmodArg0::new().with_vipf(6) // 18-bit pixel
    ) },
    { command: CmdDispon() },
    { sleep_ms: 20 },
    // { command: CmdCn2bkxsel(
    //     CmdCn2bkxselArg0::new(),
    //     CmdCn2bkxselArg1::new(),
    //     CmdCn2bkxselArg2::new(),
    //     CmdCn2bkxselArg3::new(),
    //     CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(true),
    // ) },
    // { command: CmdPorctrl(
    //     CmdPorctrlArg0::new().with_vbp(0xFF),
    //     CmdPorctrlArg1::new().with_vfp(0x0),
    // ) },
    // // { command: CmdRgbctrl(
    // //     CmdRgbctrlArg0::new()
    // //         .with_ep(false)
    // //         .with_dp(false)
    // //         .with_hsp(false)
    // //         .with_vsp(false)
    // //         .with_de_hv(true),
    // //     CmdRgbctrlArg1::new()
    // //         .with_hbp_hvrgb(16),
    // //     CmdRgbctrlArg2::new()
    // //         .with_vbp_hvrgb(8),
    // // ) },
    // { command: CmdCn2bkxsel(
    //     CmdCn2bkxselArg0::new(),
    //     CmdCn2bkxselArg1::new(),
    //     CmdCn2bkxselArg2::new(),
    //     CmdCn2bkxselArg3::new(),
    //     CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
    // ) },
    // { sleep_ms: 20 },
];
