//! Default `LicenseVerifier` implementation that wraps a `PublicKeyResolver`
//! and validates the full JWT claim set (aud/iss/exp/tenant/product/device).

use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};

use serde::Deserialize;

use crate::jws::{verify_ed25519, JwsError};
use crate::public_key_resolver::PublicKeyResolver;
use crate::LicenseVerifier;

const EXPECTED_AUDIENCE: &str = "pay_plugin";
const EXPECTED_ISSUER: &str = "subscription-platform";

#[derive(Debug, Deserialize)]
struct LicenseClaims {
    iss: Option<String>,
    aud: Option<String>,
    exp: Option<u64>,
    tenant_id: Option<String>,
    product_id: Option<String>,
    device_binding: Option<String>,
}

pub struct ResolverBackedVerifier {
    resolver: Arc<PublicKeyResolver>,
}

impl ResolverBackedVerifier {
    pub fn new(resolver: Arc<PublicKeyResolver>) -> Self {
        Self { resolver }
    }
}

impl LicenseVerifier for ResolverBackedVerifier {
    fn verify(
        &self,
        license_token: &str,
        tenant_id: &str,
        product_id: &str,
        device_fingerprint: &str,
    ) -> bool {
        verify_internal(
            &self.resolver,
            license_token,
            tenant_id,
            product_id,
            device_fingerprint,
        )
        .unwrap_or(false)
    }
}

pub fn read_tenant_id_from_license(token: &str) -> Option<String> {
    let mut parts = token.splitn(3, '.');
    let _header = parts.next()?;
    let payload_b64 = parts.next()?;
    let payload_bytes = base64::Engine::decode(
        &base64::engine::general_purpose::URL_SAFE_NO_PAD,
        payload_b64,
    )
    .ok()?;
    let claims: LicenseClaims = serde_json::from_slice(&payload_bytes).ok()?;
    claims.tenant_id
}

fn verify_internal(
    resolver: &PublicKeyResolver,
    token: &str,
    expected_tenant_id: &str,
    product_id: &str,
    device_fingerprint: &str,
) -> Result<bool, JwsError> {
    let header_b64 = token.split('.').next().ok_or(JwsError::Malformed)?;
    let header_bytes = base64::Engine::decode(
        &base64::engine::general_purpose::URL_SAFE_NO_PAD,
        header_b64,
    )
    .map_err(|_| JwsError::Malformed)?;
    let header: serde_json::Value =
        serde_json::from_slice(&header_bytes).map_err(|_| JwsError::Malformed)?;
    let kid = header
        .get("kid")
        .and_then(|value| value.as_str())
        .ok_or(JwsError::Malformed)?;

    let claimed_tenant_id = read_tenant_id_from_license(token).ok_or(JwsError::InvalidPayload)?;
    let lookup_tenant_id = if expected_tenant_id.is_empty() {
        claimed_tenant_id.as_str()
    } else {
        expected_tenant_id
    };

    let verifying_key = resolver
        .verifying_key_for(lookup_tenant_id, kid)
        .map_err(|_| JwsError::InvalidKey("public key lookup failed".to_string()))?;
    let verified = verify_ed25519(token, &verifying_key)?;

    let claims: LicenseClaims =
        serde_json::from_slice(&verified.payload).map_err(|_| JwsError::InvalidPayload)?;
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0);

    if claims.iss.as_deref() != Some(EXPECTED_ISSUER) {
        return Ok(false);
    }
    if claims.aud.as_deref() != Some(EXPECTED_AUDIENCE) {
        return Ok(false);
    }
    if let Some(exp) = claims.exp {
        if exp <= now {
            return Ok(false);
        }
    } else {
        return Ok(false);
    }
    if !expected_tenant_id.is_empty() && claims.tenant_id.as_deref() != Some(expected_tenant_id) {
        return Ok(false);
    }
    if claims.product_id.as_deref() != Some(product_id) {
        return Ok(false);
    }
    if claims.device_binding.as_deref() != Some(device_fingerprint) {
        return Ok(false);
    }
    Ok(true)
}
