use crate::dat_key::Kid;
use crate::error::DatError;
use base64::engine::general_purpose;
use std::time::SystemTime;
use base64::Engine;

const ENGINE_URL_SAFE_NO_PAD: &general_purpose::GeneralPurpose = &general_purpose::URL_SAFE_NO_PAD;

pub fn encode_base64_url_no_pad<T: AsRef<[u8]>>(b: T) -> String {
    ENGINE_URL_SAFE_NO_PAD.encode(b)
}

pub fn encode_base64_url_no_pad_out<T: AsRef<[u8]>>(b: T, out: &mut String) {
    ENGINE_URL_SAFE_NO_PAD.encode_string(b, out)
}

pub fn decode_base64_url_no_pad<T: AsRef<[u8]>>(b64: T) -> Result<Vec<u8>, DatError> {
    ENGINE_URL_SAFE_NO_PAD.decode(&b64).map_err(|_| DatError::InvalidBase64Format)
}

pub fn to_kid<T: Kid>(kid_text: &str) -> Result<T, DatError> {
    kid_text.parse::<T>().map_err(|_| DatError::InvalidDatKidFormat)
}

pub fn now_unix_timestamp() -> i64 {
    // unwrap() 으로 무시 : 시스템이 1970년 이전으로 발생해 음수 발생시 나는 오류로 무시
    SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64
}

pub fn to_utf8(vec: Vec<u8>) -> Result<String, DatError> {
    String::from_utf8(vec).map_err(|_| DatError::Utf8EncodeError)
}

pub fn get_dat_dot_indices(dat: &str) -> Result<[usize; 4], DatError> {
    let mut res = [0; 4];
    let mut count = 0;

    for (idx, _) in dat.match_indices('.') {
        if count < 4 {
            res[count] = idx;
            count += 1;
        } else {
            count = 0;
            break;
        }
    }

    if count == 4 {
        Ok(res)
    } else {
        Err(DatError::InvalidDatFormat)
    }
}