use rsa::{RsaPrivateKey, RsaPublicKey};
use rsa::pkcs1::{EncodeRsaPrivateKey, EncodeRsaPublicKey, DecodeRsaPrivateKey, DecodeRsaPublicKey, LineEnding};
use rusqlite::Connection;

pub struct ApKeys {
    pub private_key: RsaPrivateKey,
    pub public_key_pem: String,
}

pub fn load_or_generate(db: &Connection) -> ApKeys {
    // try loading from DB
    if let Ok((pub_pem, priv_pem)) = db.query_row(
        "SELECT public_pem, private_pem FROM ap_keys WHERE id = 1",
        [],
        |row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)),
    ) {
        let private_key = RsaPrivateKey::from_pkcs1_pem(&priv_pem)
            .expect("failed to parse stored RSA private key");
        let _ = RsaPublicKey::from_pkcs1_pem(&pub_pem)
            .expect("failed to parse stored RSA public key");
        return ApKeys {
            private_key,
            public_key_pem: pub_pem,
        };
    }

    // generate new 2048-bit key pair
    tracing::info!("generating RSA-2048 key pair for ActivityPub...");
    let mut rng = rsa::rand_core::OsRng;
    let private_key = RsaPrivateKey::new(&mut rng, 2048)
        .expect("failed to generate RSA key");
    let public_key = RsaPublicKey::from(&private_key);

    let pub_pem = public_key.to_pkcs1_pem(LineEnding::LF)
        .expect("failed to encode public key");
    let priv_pem = private_key.to_pkcs1_pem(LineEnding::LF)
        .expect("failed to encode private key");

    let now = chrono::Utc::now().to_rfc3339();
    db.execute(
        "INSERT INTO ap_keys (id, public_pem, private_pem, created_at) VALUES (1, ?1, ?2, ?3)",
        rusqlite::params![pub_pem, priv_pem.as_str(), now],
    ).expect("failed to store RSA keys");

    tracing::info!("RSA key pair generated and stored");

    ApKeys {
        private_key,
        public_key_pem: pub_pem,
    }
}
