use crate::{block::BLOCK, data::sub_box::s_box, keyGen::Keys};
fn std_round(block: &mut BLOCK, key: BLOCK) {
    sbox(block, true);
    shift_row(block);
    mix_columns(block);
    //*block = *block * BLOCK::new(MATRIX_MULT);
    *block = *block ^ key;
}
pub fn full_encrypt(block: &mut BLOCK, keys: &Keys) {
    block.flipyx();
    *block = *block ^ keys.keyBlocks[0];
    for i in 1..9 {
        std_round(block, keys.keyBlocks[i])
    }
    sbox(block, true);
    shift_row(block);
    *block = *block ^ keys.keyBlocks[9];
}

pub fn sbox(block: &mut BLOCK, frd: bool) {
    for row in &mut block.0 {
        for item in row {
            *item = s_box(*item, frd);
        }
    }
}

fn mix_columns(block: &mut BLOCK) {
    
    fn g_mul(mut a: u8, mut b: u8) -> u8 {
        let mut p = 0;

        for _ in 0..8 {
            if b & 1 != 0 {
                p ^= a;
            }

            let high_bit_set = a & 0x80 != 0;
            a <<= 1;

            if high_bit_set {
                a ^= 0x1b;
            }

            b >>= 1;
        }

        p
    }

    let mut output = BLOCK::new([0; 16]);

    for c in 0..4 {
        output.0[c][0] =
            g_mul(0x02, block.0[c][0]) ^ g_mul(0x03, block.0[c][1]) ^ block.0[c][2] ^ block.0[c][3];
        output.0[c][1] =
            block.0[c][0] ^ g_mul(0x02, block.0[c][1]) ^ g_mul(0x03, block.0[c][2]) ^ block.0[c][3];
        output.0[c][2] =
            block.0[c][0] ^ block.0[c][1] ^ g_mul(0x02, block.0[c][2]) ^ g_mul(0x03, block.0[c][3]);
        output.0[c][3] =
            g_mul(0x03, block.0[c][0]) ^ block.0[c][1] ^ block.0[c][2] ^ g_mul(0x02, block.0[c][3]);
    }

    *block = output;
}

#[allow(dead_code)]
fn shift_row(block: &mut BLOCK) {
    //  i was tempted just to use the .rotate_left(x) function but i thought that this may be quicker.   less to call i guess?
    for row in 1..4 {
        for _ in 0..row {
            let buf = block.0[row][3];
            for i in (0..3).rev() {
                block.0[row][(i + 1) % 4] = block.0[row][i];
            }
            block.0[row][0] = buf;
        }
    }
}
