//! # KeePass-rs Library
//!
//! Platform-independent KeePass database library.
//! Supports KDB (v1) and KDBX (v3.1, v4.0) file formats.
//!
//! ## Architecture
//! - `crypto` - Encryption algorithm abstractions and KDF engines
//! - `model` - Data models (Entry, Group, Node, Icon, etc.)
//! - `kdbx` - KDBX file I/O, KDF, merge, repair, search, XML, stream
//!
//! ## Compatibility
//! Designed to be byte-for-byte compatible with KeePassDX 4.4.3

pub mod crypto;
pub mod model;
pub mod kdbx;

pub use model::exception::{DatabaseError, DatabaseResult};

// Top-level convenience re-exports

// ─── Element (Data Models) ────────────────────────────────────────────
pub use model::{
    Database, DatabaseVersion, Entry, EntryField, Group,
    Node, NodeId, NodeType, IconImage, IconImageStandard, IconImageCustom,
    ProtectedString, MemoryProtectionConfig,
    BinaryData, BinaryPool, BinaryCache, BinaryStreamReader, BinaryStreamWriter,
    DateInstant, CompositeKey, MasterCredential,
    ChangeTracker, ChangeType, ChangeRecord, DiffResult,
    CustomData, CustomDataItem, DeletedObject, SortNodeEnum,
    Tag, parse_tags, serialize_tags,
    AutoType, AutoTypeAssociation,
    FieldReference, RefTarget,
    EntryKDB, EntryKDBX, GroupKDB, GroupKDBX,
    Template, TemplateField, TemplateFieldType,
    TraversalOrder, NodeHandler,
};

// ─── Crypto ───────────────────────────────────────────────────────────
pub use crypto::{
    CipherEngine, AesCipherEngine, ChaCha20CipherEngine, TwofishCipherEngine,
    CompressionAlgorithm, EncryptionAlgorithm,
    InnerStreamCipher,
    Salsa20InnerStream, ChaCha20InnerStream, ArcFourInnerStream,
    AesCipher, TwofishCipher, ChaCha20Cipher, Salsa20Cipher,
    AesKeyTransformer, StreamCipher,
    Argon2Kdf, Argon2Params, Argon2Type,
    HashEngine, HmacCompute,
    CipherMode, BlockMode, CryptoError, CryptoResult,
};

// ─── Signatures & Variant Dictionary ─────────────────────────────────
pub use kdbx::signature::{SignatureAlgorithm, SignatureStatus, SignatureVerifier, DigitalSignature, PublicKey};
pub use kdbx::variant_dictionary::{VariantDictionary, VdValue};

// ─── KDF ──────────────────────────────────────────────────────────────
pub use kdbx::kdf::{KdfEngine, KdfParameters};
pub use kdbx::kdf::aes_kdf::AesKdf;
pub use kdbx::kdf::argon2_kdf::Argon2Kdf as Argon2KdfEngine;
// Note: Argon2Variant is re-exported from crypto as Argon2Type alias

// ─── I/O ──────────────────────────────────────────────────────────────
pub use kdbx::file::reader::DatabaseReader;
pub use kdbx::file::writer::DatabaseWriter;

// ─── Search ───────────────────────────────────────────────────────────
pub use kdbx::search::{SearchHelper, SearchParameters, SearchResult};

// ─── Merge ────────────────────────────────────────────────────────────
pub use kdbx::merge::{DatabaseMerger, MergeStrategy, MergeResult, MergeConflict, ConflictType, ConflictResolution};

// ─── OTP ──────────────────────────────────────────────────────────────
pub use model::entry::otp::{OtpParameters, TokenCalculator, OtpType, OtpHashAlgorithm};

// ─── Repair ───────────────────────────────────────────────────────────
pub use kdbx::repair::{IntegrityVerifier, IntegrityReport, IntegrityError, IntegrityWarning, RepairResult};

// ─── Fuzz ─────────────────────────────────────────────────────────────
pub use kdbx::fuzz::{FuzzTarget, FuzzResult, FuzzOutcome};

// ─── XML ──────────────────────────────────────────────────────────────
pub use kdbx::xml::{KdbxXmlReader, KdbxXmlWriter};

/// Open a KeePass database from a reader.
///
/// Automatically detects the format (KDB, KDBX 3.1, KDBX 4.0) and reads the database.
///
/// # Example
/// ```ignore
/// use keepass_rs::{open_database, CompositeKey};
///
/// let file = std::fs::File::open("database.kdbx")?;
/// let key = CompositeKey::new().with_password(b"mypassword");
/// let db = open_database(file, &key)?;
/// println!("Opened {} entries", db.entry_count());
/// ```
pub fn open_database<R: std::io::Read>(
    reader: R,
    key: &CompositeKey,
) -> DatabaseResult<Database> {
    // Read everything into memory so we can peek at the signature and then
    // pass the full buffer to the appropriate reader.
    // Each reader internally calls detect_version, so we reset to offset 0
    // after detecting.
    use std::io::Read;
    let mut all_bytes = Vec::new();
    reader.take(100 * 1024 * 1024).read_to_end(&mut all_bytes)?;

    let mut cursor = std::io::Cursor::new(&all_bytes);
    let version = kdbx::file::reader::DatabaseReader::detect_version(&mut cursor)?;

    // Reset — each reader will re-read the signature internally.
    cursor.set_position(0);

    match version {
        DatabaseVersion::KDB => kdbx::file::kdb_reader::read_kdb(&mut cursor, key),
        DatabaseVersion::KDBX31 => kdbx::file::kdbx31_reader::read_kdbx31(&mut cursor, key),
        DatabaseVersion::KDBX4 => kdbx::file::kdbx4_reader::read_kdbx4(&mut cursor, key),
    }
}

/// Save a KeePass database to a writer.
///
/// Writes the database in the format specified by `database.version`.
///
/// # Example
/// ```ignore
/// use keepass_rs::{save_database, CompositeKey};
///
/// let mut out = std::fs::File::create("database.kdbx")?;
/// save_database(&mut out, &db, &key)?;
/// ```
pub fn save_database<W: std::io::Write>(
    writer: &mut W,
    database: &Database,
    key: &CompositeKey,
) -> DatabaseResult<()> {
    match database.version {
        DatabaseVersion::KDB => kdbx::file::kdb_writer::write_kdb(writer, database, key),
        DatabaseVersion::KDBX31 => kdbx::file::kdbx31_writer::write_kdbx31(writer, database, key),
        DatabaseVersion::KDBX4 => kdbx::file::kdbx4_writer::write_kdbx4(writer, database, key),
    }
}
