use base64::{engine::general_purpose::STANDARD, Engine as _};
use ed25519_dalek::{Signer, SigningKey, VerifyingKey};
use shared::types::LicensePayload;

pub fn load_signing_key(hex_str: &str) -> Result<SigningKey, String> {
  let bytes = hex::decode(hex_str).map_err(|e| format!("Invalid hex in signing key: {}", e))?;

  if bytes.len() != 32 {
    return Err(format!(
      "Signing key must be exactly 32 bytes (64 hex characters), got {}",
      bytes.len()
    ));
  }

  let mut key_bytes = [0u8; 32];

  key_bytes.copy_from_slice(&bytes);

  Ok(SigningKey::from_bytes(&key_bytes))
}

pub fn sign_license(
  signing_key: &SigningKey,
  license_key: &str,
  hwid: &str,
  device_count: Option<u32>,
  max_devices: Option<u32>,
  expires_at: Option<&str>,
) -> String {
  let payload = LicensePayload {
    product_id: "cleancopy".to_string(),
    license_key: license_key.to_string(),
    hwid: hwid.to_string(),
    max_devices,
    expires_at: expires_at.map(|s| s.to_string()),
    device_count,
  };

  let payload_str = serde_json::to_string(&payload).unwrap();
  let payload_b64 = STANDARD.encode(payload_str.as_bytes());

  let signature = signing_key.sign(payload_b64.as_bytes());
  let signature_b64 = STANDARD.encode(signature.to_bytes());

  format!("{}.{}", payload_b64, signature_b64)
}

pub fn verify_license(
  token: &str,
  public_key_bytes: &[u8; 32],
  current_hwid: &str,
) -> Result<LicensePayload, String> {
  shared::licensing::verify_license_with_key(token, public_key_bytes, current_hwid)
}

pub fn get_verifying_key(signing_key: &SigningKey) -> VerifyingKey {
  signing_key.verifying_key()
}

#[cfg(test)]
mod tests {
  use super::*;

  fn test_signing_key() -> SigningKey {
    let bytes = [42u8; 32];

    SigningKey::from_bytes(&bytes)
  }

  #[test]
  fn test_load_signing_key_valid() {
    let hex_str = "42".repeat(32);

    let key = load_signing_key(&hex_str);

    assert!(key.is_ok());
  }

  #[test]
  fn test_load_signing_key_invalid_hex() {
    let result = load_signing_key("not_hex");

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("Invalid hex"));
  }

  #[test]
  fn test_load_signing_key_wrong_length() {
    let hex_str = "42".repeat(16);

    let result = load_signing_key(&hex_str);

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("32 bytes"));
  }

  #[test]
  fn test_sign_license_produces_valid_token() {
    let key = test_signing_key();
    let token = sign_license(&key, "pi_test_123", "hwid_abc", Some(1), None, None);

    let parts: Vec<&str> = token.split('.').collect();

    assert_eq!(
      parts.len(),
      2,
      "Token must have exactly one period separator"
    );

    assert!(STANDARD.decode(parts[0]).is_ok());
    assert!(STANDARD.decode(parts[1]).is_ok());
  }

  #[test]
  fn test_sign_license_roundtrip() {
    let key = test_signing_key();
    let pub_key = key.verifying_key().to_bytes();
    let token = sign_license(&key, "pi_test_123", "hwid_abc", Some(2), Some(5), None);

    let payload = verify_license(&token, &pub_key, "hwid_abc").unwrap();

    assert_eq!(payload.license_key, "pi_test_123");
    assert_eq!(payload.hwid, "hwid_abc");
    assert_eq!(payload.device_count, Some(2));
    assert_eq!(payload.max_devices, Some(5));
  }

  #[test]
  fn test_sign_license_wrong_hwid_fails() {
    let key = test_signing_key();
    let pub_key = key.verifying_key().to_bytes();
    let token = sign_license(&key, "pi_test_123", "hwid_abc", Some(1), None, None);

    let result = verify_license(&token, &pub_key, "hwid_wrong");

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("Hardware ID"));
  }

  #[test]
  fn test_sign_license_wrong_key_fails() {
    let key1 = test_signing_key();
    let key2 = SigningKey::from_bytes(&[99u8; 32]);
    let pub_key2 = key2.verifying_key().to_bytes();
    let token = sign_license(&key1, "pi_test_123", "hwid_abc", Some(1), None, None);

    let result = verify_license(&token, &pub_key2, "hwid_abc");

    assert!(result.is_err());
  }

  #[test]
  fn test_sign_license_with_expires_at() {
    let key = test_signing_key();
    let pub_key = key.verifying_key().to_bytes();
    let token = sign_license(
      &key,
      "pi_test_123",
      "hwid_abc",
      Some(1),
      None,
      Some("2025-12-31"),
    );

    let payload = verify_license(&token, &pub_key, "hwid_abc").unwrap();

    assert_eq!(payload.expires_at.as_deref(), Some("2025-12-31"));
  }

  #[test]
  fn test_sign_license_unlimited_devices() {
    let key = test_signing_key();
    let pub_key = key.verifying_key().to_bytes();
    let token = sign_license(&key, "pi_test_123", "hwid_abc", Some(3), None, None);

    let payload = verify_license(&token, &pub_key, "hwid_abc").unwrap();

    assert_eq!(payload.device_count, Some(3));
    assert!(payload.max_devices.is_none());
  }
}
