# hcfs-client

Core sync engine library for HCFS. Handles encryption, signing, and the three-tree synchronization model.

## Features

- End-to-end encryption (server never sees plaintext)
- BIP-39 mnemonic-based key derivation
- Three-tree sync algorithm (inspired by Dropbox Nucleus)
- Streaming encryption for large files
- Progress callbacks for UI integration
- Conflict detection and resolution

## Usage

```rust
use hcfs_client::{
    client::HcfsClientConfig,
    drive::Drive,
    sync::{SyncConflictResolution, SyncMode},
};

// Initialize a new drive
let mut drive = Drive::new("/path/to/drive");

// Initialize with password (generates 24-word mnemonic)
let mnemonic = drive.init("secure-password", None)?;
println!("Recovery phrase: {}", mnemonic);

// Configure server connection
let config = HcfsClientConfig {
    base_url: "https://server.example.com:9999".to_string(),
    api_key: "your-api-key".to_string(),
    bearer_token: "your-user-token".to_string(),
    accept_invalid_certs: false,
};
drive.set_config(config)?;

// Unlock the drive
drive.unlock("secure-password")?;

// Sync with conflict resolver
let outcome = drive
    .sync_with_resolver(SyncMode::Interactive, |conflict| {
        SyncConflictResolution::KeepLocal
    })
    .await?;

println!("Uploaded: {} files", outcome.files_uploaded);
println!("Downloaded: {} files", outcome.files_downloaded);
```

## Key Types

### `Drive`

Main entry point for all operations.

```rust
impl Drive {
    fn new(path: &Path) -> Self;
    fn init(&mut self, password: &str, mnemonic: Option<&str>) -> Result<String>;
    fn unlock(&mut self, password: &str) -> Result<()>;
    fn is_unlocked(&self) -> bool;
    fn user_id(&self) -> Option<&str>;
    fn stage(&self) -> Result<SyncPlan>;
    async fn sync_with_resolver<F>(&mut self, mode: SyncMode, resolver: F) -> Result<SyncOutcome>;
}
```

### `SyncPlan`

Result of comparing local, remote, and synced trees.

```rust
pub struct SyncPlan {
    pub uploads: Vec<FileId>,        // Files to upload
    pub downloads: Vec<FileId>,      // Files to download
    pub local_deletes: Vec<FileId>,  // Files to delete locally
    pub remote_deletes: Vec<FileId>, // Files to delete on server
    pub conflicts: Vec<SyncConflictInfo>,
}
```

### `FileMetadata`

Per-file state tracked in each tree.

```rust
pub struct FileMetadata {
    pub path_hash: [u8; 32],       // BLAKE3 of relative path
    pub salted_hash: [u8; 32],     // BLAKE3(user_id || plaintext)
    pub size_bytes: u64,
    pub revision_seq: u64,          // Monotonic sequence number
    pub revision_id: [u8; 32],      // Unique revision identifier
    pub encryption_nonce: [u8; 24], // XChaCha20-Poly1305 nonce
}
```

## Cryptographic Stack

| Algorithm | Purpose |
|-----------|---------|
| **BIP-39** | 24-word mnemonic for key derivation and recovery |
| **Ed25519** | Digital signatures for manifest authenticity (ToS acceptance) |
| **XChaCha20-Poly1305** | File content and path encryption |
| **AES-256-GCM** | Encrypted mnemonic storage at rest |
| **PBKDF2** | Key derivation from user password |
| **BLAKE3** | Content hashing, path hashing, salted deduplication |

## Three-Tree Sync Model

Based on the [Dropbox Nucleus](https://dropbox.tech/infrastructure/rewriting-the-heart-of-our-sync-engine) approach:

```
┌─────────┐     ┌─────────┐     ┌─────────┐
│  Local  │     │ Remote  │     │ Synced  │
│  Tree   │     │  Tree   │     │  Tree   │
└────┬────┘     └────┬────┘     └────┬────┘
     │               │               │
     └───────────────┴───────────────┘
                     │
              ┌──────▼──────┐
              │ classify()  │
              │  per file   │
              └──────┬──────┘
                     │
              ┌──────▼──────┐
              │  SyncPlan   │
              └─────────────┘
```

**Trees:**
- **Local**: Current filesystem state (scanned from disk)
- **Remote**: Current server state (fetched via API)
- **Synced**: Last synchronized state (stored in `.hippius/sync_state.json`)

**Classification Logic:**

| Local | Remote | Synced | Action |
|-------|--------|--------|--------|
| A | A | A | Unchanged |
| A | - | - | LocalCreate (upload) |
| - | A | - | RemoteCreate (download) |
| A' | A | A | LocalModify (upload) |
| A | A' | A | RemoteModify (download) |
| - | A | A | LocalDelete (remote delete) |
| A | - | A | RemoteDelete (local delete) |
| A' | A'' | A | **Conflict** (ModifyModify) |
| A' | - | A | **Conflict** (ModifyDelete) |
| - | A' | A | **Conflict** (DeleteModify) |
| A | B | - | **Conflict** (CreateCreate) |

## Conflict Resolution

```rust
pub enum SyncConflictResolution {
    /// Keep local version (upload, overwriting remote)
    KeepLocal,
    /// Accept remote version (download, overwriting local)
    AcceptRemote,
    /// Keep both: save local as .conflict, download remote
    KeepBoth,
    /// Skip this conflict for now
    Skip,
}
```

## Progress Callbacks

```rust
use hcfs_client::sync::SyncProgress;

let progress = SyncProgress {
    on_upload_progress: Some(Arc::new(|bytes, total, path| {
        println!("Uploading {}: {}/{}", path.unwrap_or(""), bytes, total);
    })),
    on_download_progress: Some(Arc::new(|bytes, total, path| {
        println!("Downloading {}: {}/{}", path.unwrap_or(""), bytes, total);
    })),
    on_encrypt_progress: None,
    on_decrypt_progress: None,
    on_scan_progress: Some(Arc::new(|count, path| {
        println!("Scanned {} files, current: {}", count, path.unwrap_or(""));
    })),
    on_fetch_state_progress: Some(Arc::new(|fetched, total| {
        println!("Fetched {}/{} remote entries", fetched, total);
    })),
};

drive.set_progress_handlers(progress);
```

## Error Handling

```rust
pub enum SyncError {
    ConflictsDetected(usize),    // Non-interactive mode with conflicts
    StaleBase { file_id, ... },  // Optimistic concurrency failure
    HashMismatch(FileId),        // Integrity check failed
    UploadFailed(String),
    DownloadFailed(String),
    NotInitialized,
    // ... more variants
}
```
