//! Key serialization: PKCS#1 (RSA), SEC1 (ECC), SPKI, PKCS#8.
//!
//! Implements `to_*_der` / `from_*_der` and `to_*_pem` / `from_*_pem`
//! on the existing key types in `rsa::rsa` and `ecc::curves` /
//! `ecc::eddsa`.

use super::der::*;
use super::pem::*;
use crate::ecc::curves::{PublicKey as EcPublicKey, SecretKey as EcSecretKey};
use crate::ecc::eddsa::{Ed25519PublicKey, Ed25519SecretKey};
use crate::rsa::bigint::BigInt;
use crate::rsa::rsa::{RsaPublicKey, RsaSecretKey};

// ====================================================================
// RSA — PKCS#1 DER (RFC 8017 §A.1)
// ====================================================================

impl RsaPublicKey {
    /// Encode as PKCS#1 DER (`RSAPublicKey ::= SEQUENCE { n INTEGER, e INTEGER }`).
    pub fn to_pkcs1_der(&self) -> Vec<u8> {
        let n_bytes = self.n.to_be_bytes(self.n.byte_len());
        let e_bytes = self.e.to_be_bytes(self.e.byte_len());
        let mut inner = DerEncoder::new();
        inner.integer(&n_bytes);
        inner.integer(&e_bytes);
        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Parse from PKCS#1 DER.
    pub fn from_pkcs1_der(der: &[u8]) -> Option<Self> {
        let mut dec = DerDecoder::new(der);
        let mut seq = dec.read_sequence()?;
        let n = BigInt::from_be_bytes(seq.read_integer()?);
        let e = BigInt::from_be_bytes(seq.read_integer()?);
        if !seq.is_empty() {
            return None;
        }
        Some(Self { n, e })
    }

    /// Encode as SubjectPublicKeyInfo DER (RFC 5280).
    pub fn to_spki_der(&self) -> Vec<u8> {
        let pkcs1 = self.to_pkcs1_der();
        // AlgorithmIdentifier: SEQUENCE { rsaEncryption OID, NULL }
        let mut algo = DerEncoder::new();
        algo.oid(OID_RSA);
        algo.null();
        let algo_bytes = algo.finish();
        let mut inner = DerEncoder::new();
        inner.sequence(&algo_bytes);
        inner.bit_string(&pkcs1);
        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Parse from SubjectPublicKeyInfo DER.
    pub fn from_spki_der(der: &[u8]) -> Option<Self> {
        let mut dec = DerDecoder::new(der);
        let mut seq = dec.read_sequence()?;
        let mut algo_seq = seq.read_sequence()?;
        let oid = algo_seq.read_oid()?;
        if oid != OID_RSA {
            return None;
        }
        algo_seq.read_null()?;
        let pk_bits = seq.read_bit_string()?;
        Self::from_pkcs1_der(pk_bits)
    }

    /// Encode as PKCS#1 PEM.
    pub fn to_pkcs1_pem(&self) -> String {
        pem_encode("RSA PUBLIC KEY", &self.to_pkcs1_der())
    }
    /// Parse from PKCS#1 PEM.
    pub fn from_pkcs1_pem(pem: &str) -> Option<Self> {
        Self::from_pkcs1_der(&pem_decode("RSA PUBLIC KEY", pem)?)
    }
    /// Encode as SPKI PEM.
    pub fn to_spki_pem(&self) -> String {
        pem_encode("PUBLIC KEY", &self.to_spki_der())
    }
    /// Parse from SPKI PEM.
    pub fn from_spki_pem(pem: &str) -> Option<Self> {
        Self::from_spki_der(&pem_decode("PUBLIC KEY", pem)?)
    }
}

impl RsaSecretKey {
    /// Encode as PKCS#1 DER (`RSAPrivateKey`, RFC 8017 §A.1.2).
    pub fn to_pkcs1_der(&self) -> Vec<u8> {
        let n = self.n.to_be_bytes(self.n.byte_len());
        let e_val = BigInt::from_be_bytes(&[0x01, 0x00, 0x01]); // 65537
        let e = e_val.to_be_bytes(e_val.byte_len());
        let d = self.d.to_be_bytes(self.d.byte_len());
        let p = self.p.to_be_bytes(self.p.byte_len());
        let q = self.q.to_be_bytes(self.q.byte_len());
        let dp = self.dp.to_be_bytes(self.dp.byte_len());
        let dq = self.dq.to_be_bytes(self.dq.byte_len());
        let qinv = self.qinv.to_be_bytes(self.qinv.byte_len());

        let mut inner = DerEncoder::new();
        inner.integer_u64(0); // version
        inner.integer(&n);
        inner.integer(&e);
        inner.integer(&d);
        inner.integer(&p);
        inner.integer(&q);
        inner.integer(&dp);
        inner.integer(&dq);
        inner.integer(&qinv);
        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Parse from PKCS#1 DER.
    pub fn from_pkcs1_der(der: &[u8]) -> Option<Self> {
        let mut dec = DerDecoder::new(der);
        let mut seq = dec.read_sequence()?;
        let version = seq.read_integer_u64()?;
        if version != 0 {
            return None;
        } // only two-prime RSA
        let n = BigInt::from_be_bytes(seq.read_integer()?);
        let _e = seq.read_integer()?; // public exponent (we store it in pk)
        let d = BigInt::from_be_bytes(seq.read_integer()?);
        let p = BigInt::from_be_bytes(seq.read_integer()?);
        let q = BigInt::from_be_bytes(seq.read_integer()?);
        let dp = BigInt::from_be_bytes(seq.read_integer()?);
        let dq = BigInt::from_be_bytes(seq.read_integer()?);
        let qinv = BigInt::from_be_bytes(seq.read_integer()?);
        Some(Self {
            n,
            d,
            p,
            q,
            dp,
            dq,
            qinv,
        })
    }

    /// Encode as PKCS#1 PEM.
    pub fn to_pkcs1_pem(&self) -> String {
        pem_encode("RSA PRIVATE KEY", &self.to_pkcs1_der())
    }
    /// Parse from PKCS#1 PEM.
    pub fn from_pkcs1_pem(pem: &str) -> Option<Self> {
        Self::from_pkcs1_der(&pem_decode("RSA PRIVATE KEY", pem)?)
    }
}

// ====================================================================
// ECC — SPKI (public) + PKCS#8 (private) + SEC1 (private)
// ====================================================================

/// Curve identifier for ECC key serialization.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EcCurve {
    /// NIST P-256 / secp256r1.
    P256,
    /// NIST P-384 / secp384r1.
    P384,
    /// NIST P-521 / secp521r1.
    P521,
    /// secp256k1.
    Secp256k1,
    /// brainpoolP256r1.
    BrainpoolP256r1,
    /// brainpoolP384r1.
    BrainpoolP384r1,
    /// brainpoolP512r1.
    BrainpoolP512r1,
}

impl EcCurve {
    fn oid(self) -> &'static [u8] {
        match self {
            EcCurve::P256 => OID_SECP256R1,
            EcCurve::P384 => OID_SECP384R1,
            EcCurve::P521 => OID_SECP521R1,
            EcCurve::Secp256k1 => OID_SECP256K1,
            EcCurve::BrainpoolP256r1 => OID_BRAINPOOL_P256R1,
            EcCurve::BrainpoolP384r1 => OID_BRAINPOOL_P384R1,
            EcCurve::BrainpoolP512r1 => OID_BRAINPOOL_P512R1,
        }
    }

    fn from_oid(oid: &[u8]) -> Option<Self> {
        match oid {
            x if x == OID_SECP256R1 => Some(EcCurve::P256),
            x if x == OID_SECP384R1 => Some(EcCurve::P384),
            x if x == OID_SECP521R1 => Some(EcCurve::P521),
            x if x == OID_SECP256K1 => Some(EcCurve::Secp256k1),
            x if x == OID_BRAINPOOL_P256R1 => Some(EcCurve::BrainpoolP256r1),
            x if x == OID_BRAINPOOL_P384R1 => Some(EcCurve::BrainpoolP384r1),
            x if x == OID_BRAINPOOL_P512R1 => Some(EcCurve::BrainpoolP512r1),
            _ => None,
        }
    }
}

impl EcPublicKey {
    /// Encode as SubjectPublicKeyInfo DER (RFC 5480).
    pub fn to_spki_der(&self, curve: EcCurve) -> Vec<u8> {
        // AlgorithmIdentifier: SEQUENCE { id-ecPublicKey OID, curve OID }
        let mut algo = DerEncoder::new();
        algo.oid(OID_EC_PUBLIC_KEY);
        algo.oid(curve.oid());
        let algo_bytes = algo.finish();
        let mut inner = DerEncoder::new();
        inner.sequence(&algo_bytes);
        inner.bit_string(&self.bytes);
        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Parse from SubjectPublicKeyInfo DER. Returns `(key, curve)`.
    pub fn from_spki_der(der: &[u8]) -> Option<(Self, EcCurve)> {
        let mut dec = DerDecoder::new(der);
        let mut seq = dec.read_sequence()?;
        let mut algo_seq = seq.read_sequence()?;
        let oid = algo_seq.read_oid()?;
        if oid != OID_EC_PUBLIC_KEY {
            return None;
        }
        let curve_oid = algo_seq.read_oid()?;
        let curve = EcCurve::from_oid(curve_oid)?;
        let pk_bits = seq.read_bit_string()?;
        Some((
            Self {
                bytes: pk_bits.to_vec(),
            },
            curve,
        ))
    }

    /// Encode as SPKI PEM.
    pub fn to_spki_pem(&self, curve: EcCurve) -> String {
        pem_encode("PUBLIC KEY", &self.to_spki_der(curve))
    }

    /// Parse from SPKI PEM.
    pub fn from_spki_pem(pem: &str) -> Option<(Self, EcCurve)> {
        Self::from_spki_der(&pem_decode("PUBLIC KEY", pem)?)
    }
}

impl EcSecretKey {
    /// Encode as SEC1 DER (RFC 5915: `ECPrivateKey`).
    pub fn to_sec1_der(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> Vec<u8> {
        let mut inner = DerEncoder::new();
        inner.integer_u64(1); // version

        inner.octet_string(&self.bytes);

        // [0] EXPLICIT curve OID (optional but recommended)
        {
            let mut oid_enc = DerEncoder::new();
            oid_enc.oid(curve.oid());
            let oid_bytes = oid_enc.finish();
            inner.context_explicit(0, &oid_bytes);
        }

        // [1] EXPLICIT public key BIT STRING (optional)
        if let Some(pk) = public_key {
            let mut bs = DerEncoder::new();
            bs.bit_string(&pk.bytes);
            let bs_bytes = bs.finish();
            inner.context_explicit(1, &bs_bytes);
        }

        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Parse from SEC1 DER. Returns `(secret_key, curve, optional_public_key)`.
    pub fn from_sec1_der(der: &[u8]) -> Option<(Self, EcCurve, Option<EcPublicKey>)> {
        let mut dec = DerDecoder::new(der);
        let mut seq = dec.read_sequence()?;
        let version = seq.read_integer_u64()?;
        if version != 1 {
            return None;
        }
        let sk_bytes = seq.read_octet_string()?;

        // [0] curve OID
        let mut ctx0 = seq.read_context_explicit(0)?;
        let curve_oid = ctx0.read_oid()?;
        let curve = EcCurve::from_oid(curve_oid)?;

        // [1] public key (optional)
        let pk = if let Some(mut ctx1) = seq.read_context_explicit(1) {
            let pk_bits = ctx1.read_bit_string()?;
            Some(EcPublicKey {
                bytes: pk_bits.to_vec(),
            })
        } else {
            None
        };

        Some((
            Self {
                bytes: sk_bytes.to_vec(),
            },
            curve,
            pk,
        ))
    }

    /// Encode as PKCS#8 DER (RFC 5958).
    pub fn to_pkcs8_der(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> Vec<u8> {
        let sec1 = self.to_sec1_der(curve, public_key);
        // AlgorithmIdentifier: SEQUENCE { id-ecPublicKey, curve OID }
        let mut algo = DerEncoder::new();
        algo.oid(OID_EC_PUBLIC_KEY);
        algo.oid(curve.oid());
        let algo_bytes = algo.finish();

        let mut inner = DerEncoder::new();
        inner.integer_u64(0); // version (v1)
        inner.sequence(&algo_bytes);
        inner.octet_string(&sec1);
        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Encode as SEC1 PEM.
    pub fn to_sec1_pem(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> String {
        pem_encode("EC PRIVATE KEY", &self.to_sec1_der(curve, public_key))
    }

    /// Encode as PKCS#8 PEM.
    pub fn to_pkcs8_pem(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> String {
        pem_encode("PRIVATE KEY", &self.to_pkcs8_der(curve, public_key))
    }
}

// ====================================================================
// Ed25519 — SPKI (public) + PKCS#8 (private) per RFC 8037
// ====================================================================

impl Ed25519PublicKey {
    /// Encode as SubjectPublicKeyInfo DER (RFC 8037).
    pub fn to_spki_der(&self) -> Vec<u8> {
        // AlgorithmIdentifier: SEQUENCE { id-Ed25519 } — no parameters
        let mut algo = DerEncoder::new();
        algo.oid(OID_ED25519);
        let algo_bytes = algo.finish();
        let mut inner = DerEncoder::new();
        inner.sequence(&algo_bytes);
        inner.bit_string(&self.0);
        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Parse from SPKI DER.
    pub fn from_spki_der(der: &[u8]) -> Option<Self> {
        let mut dec = DerDecoder::new(der);
        let mut seq = dec.read_sequence()?;
        let mut algo_seq = seq.read_sequence()?;
        let oid = algo_seq.read_oid()?;
        if oid != OID_ED25519 {
            return None;
        }
        let pk_bits = seq.read_bit_string()?;
        if pk_bits.len() != 32 {
            return None;
        }
        let mut out = [0u8; 32];
        out.copy_from_slice(pk_bits);
        Some(Self(out))
    }

    /// Encode as SPKI PEM.
    pub fn to_spki_pem(&self) -> String {
        pem_encode("PUBLIC KEY", &self.to_spki_der())
    }
    /// Parse from SPKI PEM.
    pub fn from_spki_pem(pem: &str) -> Option<Self> {
        Self::from_spki_der(&pem_decode("PUBLIC KEY", pem)?)
    }
}

impl Ed25519SecretKey {
    /// Encode as PKCS#8 DER (RFC 8037).
    pub fn to_pkcs8_der(&self) -> Vec<u8> {
        // The "private key" in PKCS#8 for Ed25519 is an OCTET STRING
        // containing the 32-byte seed, itself wrapped in an OCTET STRING.
        let mut seed_enc = DerEncoder::new();
        seed_enc.octet_string(&self.0);
        let seed_der = seed_enc.finish();

        let mut algo = DerEncoder::new();
        algo.oid(OID_ED25519);
        let algo_bytes = algo.finish();

        let mut inner = DerEncoder::new();
        inner.integer_u64(0); // version
        inner.sequence(&algo_bytes);
        inner.octet_string(&seed_der);
        let content = inner.finish();
        let mut outer = DerEncoder::new();
        outer.sequence(&content);
        outer.finish()
    }

    /// Parse from PKCS#8 DER.
    pub fn from_pkcs8_der(der: &[u8]) -> Option<Self> {
        let mut dec = DerDecoder::new(der);
        let mut seq = dec.read_sequence()?;
        let version = seq.read_integer_u64()?;
        if version != 0 {
            return None;
        }
        let mut algo_seq = seq.read_sequence()?;
        let oid = algo_seq.read_oid()?;
        if oid != OID_ED25519 {
            return None;
        }
        let pk_octet = seq.read_octet_string()?;
        // Inner OCTET STRING wrapping the 32-byte seed.
        let mut inner = DerDecoder::new(pk_octet);
        let seed = inner.read_octet_string()?;
        if seed.len() != 32 {
            return None;
        }
        let mut out = [0u8; 32];
        out.copy_from_slice(seed);
        Some(Self(out))
    }

    /// Encode as PKCS#8 PEM.
    pub fn to_pkcs8_pem(&self) -> String {
        pem_encode("PRIVATE KEY", &self.to_pkcs8_der())
    }
    /// Parse from PKCS#8 PEM.
    pub fn from_pkcs8_pem(pem: &str) -> Option<Self> {
        Self::from_pkcs8_der(&pem_decode("PRIVATE KEY", pem)?)
    }
}

// ====================================================================
// Tests
// ====================================================================

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ecc::eddsa::ed25519_keygen;

    fn rng_fill(buf: &mut [u8]) {
        static mut CTR: u64 = 0xdeadbeef;
        for b in buf.iter_mut() {
            unsafe {
                CTR = CTR.wrapping_mul(6364136223846793005).wrapping_add(1);
                *b = (CTR >> 33) as u8;
            }
        }
    }

    // ---------- RSA ----------

    #[test]
    fn rsa_pkcs1_roundtrip() {
        let (pk, sk) = crate::rsa::rsa::rsa_keygen(1024, &mut rng_fill);

        let pk_der = pk.to_pkcs1_der();
        let pk_back = RsaPublicKey::from_pkcs1_der(&pk_der).unwrap();
        assert_eq!(
            pk_back.n.to_be_bytes(pk.n.byte_len()),
            pk.n.to_be_bytes(pk.n.byte_len())
        );
        assert_eq!(
            pk_back.e.to_be_bytes(pk.e.byte_len()),
            pk.e.to_be_bytes(pk.e.byte_len())
        );

        let sk_der = sk.to_pkcs1_der();
        let sk_back = RsaSecretKey::from_pkcs1_der(&sk_der).unwrap();
        assert_eq!(
            sk_back.n.to_be_bytes(sk.n.byte_len()),
            sk.n.to_be_bytes(sk.n.byte_len())
        );
        assert_eq!(
            sk_back.p.to_be_bytes(sk.p.byte_len()),
            sk.p.to_be_bytes(sk.p.byte_len())
        );
    }

    #[test]
    fn rsa_spki_roundtrip() {
        let (pk, _) = crate::rsa::rsa::rsa_keygen(1024, &mut rng_fill);
        let der = pk.to_spki_der();
        let pk_back = RsaPublicKey::from_spki_der(&der).unwrap();
        assert_eq!(
            pk_back.n.to_be_bytes(pk.n.byte_len()),
            pk.n.to_be_bytes(pk.n.byte_len())
        );
    }

    #[test]
    fn rsa_pem_roundtrip() {
        let (pk, sk) = crate::rsa::rsa::rsa_keygen(1024, &mut rng_fill);
        let pk_pem = pk.to_pkcs1_pem();
        assert!(pk_pem.contains("-----BEGIN RSA PUBLIC KEY-----"));
        let pk_back = RsaPublicKey::from_pkcs1_pem(&pk_pem).unwrap();
        assert_eq!(
            pk_back.n.to_be_bytes(pk.n.byte_len()),
            pk.n.to_be_bytes(pk.n.byte_len())
        );

        let sk_pem = sk.to_pkcs1_pem();
        assert!(sk_pem.contains("-----BEGIN RSA PRIVATE KEY-----"));
        let sk_back = RsaSecretKey::from_pkcs1_pem(&sk_pem).unwrap();
        assert_eq!(
            sk_back.p.to_be_bytes(sk.p.byte_len()),
            sk.p.to_be_bytes(sk.p.byte_len())
        );
    }

    // ---------- ECC P-256 ----------

    #[test]
    fn ec_spki_roundtrip() {
        use crate::ecc::curves::{CryptoRng, Curve, P256};
        struct Rng(u64);
        impl CryptoRng for Rng {
            fn fill_bytes(&mut self, dest: &mut [u8]) {
                for b in dest {
                    self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1);
                    *b = (self.0 >> 33) as u8;
                }
            }
        }
        let (pk, _sk) = P256::keygen(&mut Rng(0xCAFE));
        let der = pk.to_spki_der(EcCurve::P256);
        let (pk_back, curve) = EcPublicKey::from_spki_der(&der).unwrap();
        assert_eq!(curve, EcCurve::P256);
        assert_eq!(pk_back.bytes, pk.bytes);
    }

    #[test]
    fn ec_sec1_roundtrip() {
        use crate::ecc::curves::{CryptoRng, Curve, P256};
        struct Rng(u64);
        impl CryptoRng for Rng {
            fn fill_bytes(&mut self, dest: &mut [u8]) {
                for b in dest {
                    self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1);
                    *b = (self.0 >> 33) as u8;
                }
            }
        }
        let (pk, sk) = P256::keygen(&mut Rng(0xBEEF));
        let der = sk.to_sec1_der(EcCurve::P256, Some(&pk));
        let (sk_back, curve, pk_back) = EcSecretKey::from_sec1_der(&der).unwrap();
        assert_eq!(curve, EcCurve::P256);
        assert_eq!(sk_back.bytes, sk.bytes);
        assert_eq!(pk_back.unwrap().bytes, pk.bytes);
    }

    #[test]
    fn ec_pem_roundtrip() {
        use crate::ecc::curves::{CryptoRng, Curve, P256};
        struct Rng(u64);
        impl CryptoRng for Rng {
            fn fill_bytes(&mut self, dest: &mut [u8]) {
                for b in dest {
                    self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1);
                    *b = (self.0 >> 33) as u8;
                }
            }
        }
        let (pk, sk) = P256::keygen(&mut Rng(0xFACE));
        let pem = pk.to_spki_pem(EcCurve::P256);
        assert!(pem.contains("-----BEGIN PUBLIC KEY-----"));
        let (pk_back, _) = EcPublicKey::from_spki_pem(&pem).unwrap();
        assert_eq!(pk_back.bytes, pk.bytes);

        let sk_pem = sk.to_sec1_pem(EcCurve::P256, None);
        assert!(sk_pem.contains("-----BEGIN EC PRIVATE KEY-----"));
    }

    // ---------- Ed25519 ----------

    #[test]
    fn ed25519_spki_roundtrip() {
        let seed = [0x42u8; 32];
        let (pk, _sk) = ed25519_keygen(&seed);
        let der = pk.to_spki_der();
        let pk_back = Ed25519PublicKey::from_spki_der(&der).unwrap();
        assert_eq!(pk_back.0, pk.0);
    }

    #[test]
    fn ed25519_pkcs8_roundtrip() {
        let seed = [0x42u8; 32];
        let (_pk, sk) = ed25519_keygen(&seed);
        let der = sk.to_pkcs8_der();
        let sk_back = Ed25519SecretKey::from_pkcs8_der(&der).unwrap();
        assert_eq!(sk_back.0, sk.0);
    }

    #[test]
    fn ed25519_pem_roundtrip() {
        let seed = [0x42u8; 32];
        let (pk, sk) = ed25519_keygen(&seed);
        let pem = pk.to_spki_pem();
        assert!(pem.contains("-----BEGIN PUBLIC KEY-----"));
        let pk_back = Ed25519PublicKey::from_spki_pem(&pem).unwrap();
        assert_eq!(pk_back.0, pk.0);

        let sk_pem = sk.to_pkcs8_pem();
        assert!(sk_pem.contains("-----BEGIN PRIVATE KEY-----"));
        let sk_back = Ed25519SecretKey::from_pkcs8_pem(&sk_pem).unwrap();
        assert_eq!(sk_back.0, sk.0);
    }
}
