use parquet2::{schema::types::TimeUnit, types::int96_to_i64_ns};

pub fn convert_i128(value: &[u8], n: usize) -> i128 {
    // Copy the fixed-size byte value to the start of a 16 byte stack
    // allocated buffer, then use an arithmetic right shift to fill in
    // MSBs, which accounts for leading 1's in negative (two's complement)
    // values.
    let mut bytes = [0u8; 16];
    bytes[..n].copy_from_slice(value);
    i128::from_be_bytes(bytes) >> (8 * (16 - n))
}
#[inline]
fn int96_to_i64_us(value: [u32; 3]) -> i64 {
    const JULIAN_DAY_OF_EPOCH: i64 = 2_440_588;
    const SECONDS_PER_DAY: i64 = 86_400;
    const MICROS_PER_SECOND: i64 = 1_000_000;

    let day = i64::from(value[2]);
    let microseconds = ((i64::from(value[1]) << 32) + i64::from(value[0])) / 1_000;
    let seconds = (day - JULIAN_DAY_OF_EPOCH) * SECONDS_PER_DAY;

    seconds * MICROS_PER_SECOND + microseconds
}

#[inline]
fn int96_to_i64_ms(value: [u32; 3]) -> i64 {
    const JULIAN_DAY_OF_EPOCH: i64 = 2_440_588;
    const SECONDS_PER_DAY: i64 = 86_400;
    const MILLIS_PER_SECOND: i64 = 1_000;

    let day = i64::from(value[2]);
    let milliseconds = ((i64::from(value[1]) << 32) + i64::from(value[0])) / 1_000_000;
    let seconds = (day - JULIAN_DAY_OF_EPOCH) * SECONDS_PER_DAY;

    seconds * MILLIS_PER_SECOND + milliseconds
}

#[inline]
pub fn convert_i96_to_i64_timestamp(value: [u32; 3], tu: TimeUnit) -> i64 {
    match tu {
        TimeUnit::Nanoseconds => int96_to_i64_ns(value),
        TimeUnit::Microseconds => int96_to_i64_us(value),
        TimeUnit::Milliseconds => int96_to_i64_ms(value),
    }
}
