use crate::{RingspaceError, joined_ring, managed_ring, member, site};
use base64::{
    Engine as _, engine::general_purpose::STANDARD,
    engine::general_purpose::URL_SAFE_NO_PAD as BASE64URL,
};
use sqlx::sqlite::SqliteConnection;

///
/// Post migration for migration 2. This re-encodes all base64 data stored in the database (keys) in base64url
/// format. That's what we're using for manifests, so no reason to use two different formats.
///
pub async fn post_migration_002(conn: &mut SqliteConnection) -> Result<(), RingspaceError> {
    // Managed Rings
    let managed_rings = managed_ring::list(&mut *conn).await?;
    for mut ring in managed_rings {
        println!("Re-encoding keys for managed ring {}", ring.url);
        let private_encryption_key_bytes = STANDARD.decode(ring.private_encryption_key)?;
        let public_encryption_key_bytes = STANDARD.decode(ring.public_encryption_key)?;
        let private_signing_key_bytes = STANDARD.decode(ring.private_signing_key)?;
        let public_signing_key_bytes = STANDARD.decode(ring.public_signing_key)?;

        ring.private_encryption_key = BASE64URL.encode(private_encryption_key_bytes);
        ring.public_encryption_key = BASE64URL.encode(public_encryption_key_bytes);
        ring.private_signing_key = BASE64URL.encode(private_signing_key_bytes);
        ring.public_signing_key = BASE64URL.encode(public_signing_key_bytes);
        ring.save(&mut *conn).await?;
        println!("Keys re-encoded for managed ring {}", ring.url);
    }

    // Joined Rings
    let joined_rings = joined_ring::list(&mut *conn).await?;
    for mut ring in joined_rings {
        println!("Re-encoding keys for joined ring {}", ring.url);
        let public_encryption_key_bytes = STANDARD.decode(ring.public_encryption_key)?;
        let public_signing_key_bytes = STANDARD.decode(ring.public_signing_key)?;

        ring.public_encryption_key = BASE64URL.encode(public_encryption_key_bytes);
        ring.public_signing_key = BASE64URL.encode(public_signing_key_bytes);
        ring.save(&mut *conn).await?;
        println!("Keys re-encoded for joined ring {}", &ring.url);
    }

    // Sites
    let sites = site::list(&mut *conn).await?;
    for mut site in sites {
        println!("Re-encoding keys for site {}", site.url);
        let site_private_signing_bytes = STANDARD.decode(site.private_signing_key)?;
        let site_public_signing_bytes = STANDARD.decode(site.public_signing_key)?;

        site.private_signing_key = BASE64URL.encode(site_private_signing_bytes);
        site.public_signing_key = BASE64URL.encode(site_public_signing_bytes);

        site.save(&mut *conn).await?;

        println!("Keys re-encoded for site {}", site.url);
    }

    // Members
    let members = member::list_all(&mut *conn).await?;
    for mut member in members {
        println!("Re-encoding key for member {}", member.url);
        let member_public_signing_bytes = STANDARD.decode(member.public_signing_key)?;
        member.public_signing_key = BASE64URL.encode(member_public_signing_bytes);
        member.save(&mut *conn).await?;
        println!("Key re-encoded for member {}", member.url);
    }

    Ok(())
}
