use napi::{bindgen_prelude::*, Error, Status};
use napi_derive::napi;

static CHAR_COLLECTION: &str = "0123456789abcdefghijklmnopqrstuvwxyz";

// -- NAPI exports --

#[napi]
pub enum IdConvertType {
  MastodonId,
  CalckeyId,
}

#[napi]
pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result<String> {
  use IdConvertType::*;
  match id_convert_type {
    MastodonId => {
      let mut out: i64 = 0;
      for (i, c) in in_id.to_lowercase().chars().rev().enumerate() {
        out += num_from_char(c)? as i64 * 36_i64.pow(i as u32);
      }

      Ok(out.to_string())
    }
    CalckeyId => {
      let mut input: i64 = match in_id.parse() {
        Ok(s) => s,
        Err(_) => {
          return Err(Error::new(
            Status::InvalidArg,
            "Unable to parse ID as MasstodonId",
          ))
        }
      };
      let mut out = String::new();

      while input != 0 {
        out.insert(0, char_from_num((input % 36) as u8)?);
        input /= 36;
      }

      Ok(out)
    }
  }
}

// -- end --

#[inline(always)]
fn num_from_char(character: char) -> napi::Result<u8> {
  for (i, c) in CHAR_COLLECTION.chars().enumerate() {
    if c == character {
      return Ok(i as u8);
    }
  }

  Err(Error::new(
    Status::InvalidArg,
    "Invalid character in parsed base36 id",
  ))
}

#[inline(always)]
fn char_from_num(number: u8) -> napi::Result<char> {
  CHAR_COLLECTION
    .chars()
    .nth(number as usize)
    .ok_or(Error::from_status(Status::Unknown))
}