use base64::Engine;
use base64::engine::general_purpose::{URL_SAFE, URL_SAFE_NO_PAD};
use serde_json::Value;

use super::json::strip_newlines;

pub fn decode_payload(token: &str) -> Option<String> {
    let payload = token.split('.').nth(1)?;
    if payload.is_empty() {
        return None;
    }

    let decoded = URL_SAFE_NO_PAD
        .decode(payload)
        .or_else(|_| URL_SAFE.decode(payload))
        .ok()?;
    String::from_utf8(decoded).ok()
}

pub fn decode_payload_json(token: &str) -> Option<Value> {
    let payload = decode_payload(token)?;
    serde_json::from_str(&payload).ok()
}

pub fn identity_from_payload(payload: &Value) -> Option<String> {
    nested_string(payload, "https://api.openai.com/auth", "chatgpt_user_id")
        .or_else(|| nested_string(payload, "https://api.openai.com/auth", "user_id"))
        .or_else(|| top_level_string(payload, "sub"))
        .or_else(|| top_level_string(payload, "email"))
}

pub fn email_from_payload(payload: &Value) -> Option<String> {
    top_level_string(payload, "email")
        .or_else(|| nested_string(payload, "https://api.openai.com/auth", "email"))
}

fn nested_string(payload: &Value, parent: &str, key: &str) -> Option<String> {
    payload
        .get(parent)
        .and_then(|value| value.get(key))
        .and_then(|value| value.as_str())
        .map(strip_newlines)
}

fn top_level_string(payload: &Value, key: &str) -> Option<String> {
    payload
        .get(key)
        .and_then(|value| value.as_str())
        .map(strip_newlines)
}
