# PDFCrypt - PDF Encryption/Decryption Utility

A powerful Python utility for encrypting and decrypting PDF files with strong security features and batch processing capabilities.

## Features

- 🔐 **Strong Encryption**: Uses 128-bit AES encryption for PDF security
- 📚 **Batch Processing**: Process multiple PDF files concurrently
- ⚙️ **Configurable**: Persistent configuration with automatic saving
- 🚀 **High Performance**: Multi-threaded processing for faster operations
- 🛡️ **Secure**: Proper resource cleanup and error handling
- 📊 **Performance Monitoring**: Built-in benchmarking and profiling

## Installation

```bash
pip install pytola-pdfcrypt
```

Or install from source:

```bash
cd pytola/pdfcrypt
pip install .
```

## Quick Start

### Command Line Usage

```bash
# Encrypt all unencrypted PDFs in current directory
pdfcrypt encrypt mysecretpassword

# Decrypt all encrypted PDFs in current directory
pdfcrypt decrypt mysecretpassword

# Use custom number of worker threads
pdfcrypt encrypt mypassword --workers 8
```

### Python API

```python
from pytola.office.pdfcrypt.pdfcrypt import encrypt_pdf, decrypt_pdf, is_encrypted
from pathlib import Path

# Check if a PDF is encrypted
pdf_file = Path("document.pdf")
if not is_encrypted(pdf_file):
    # Encrypt the file
    original, encrypted = encrypt_pdf(pdf_file, "mypassword")
    print(f"Encrypted file saved as: {encrypted}")

# Decrypt a file
encrypted_file = Path("document.enc.pdf")
original, decrypted = decrypt_pdf(encrypted_file, "mypassword")
print(f"Decrypted file saved as: {decrypted}")
```

## Configuration

PDFCrypt automatically saves your preferences to `~/.pytola/pdfcrypt.json`:

```json
{
    "max_workers": 4,
    "default_password": "",
    "output_suffix_encrypted": ".enc.pdf",
    "output_suffix_decrypted": ".dec.pdf"
}
```

Configuration is loaded automatically on startup and saved when the program exits.

## Advanced Usage

### Custom Configuration

```python
from pytola.office.pdfcrypt.pdfcrypt import PDFCryptConfig, conf

# Modify configuration
conf.max_workers = 8
conf.output_suffix_encrypted = ".protected.pdf"

# Access cached properties
print(f"Configuration loaded: {conf.is_configured}")
print(f"Config summary: {conf.config_summary}")
```

### Batch Processing

```python
from pytola.office.pdfcrypt.pdfcrypt import encrypt, decrypt
from pathlib import Path

# Set password and process all files
encrypt(ex_pwd)  # Encrypts all unencrypted PDFs
decrypt(ex_pwd)  # Decrypts all encrypted PDFs
```

## Performance

PDFCrypt is optimized for performance:

- **Multi-threading**: Process multiple files simultaneously
- **Memory efficient**: Proper resource cleanup prevents memory leaks
- **Cached configuration**: Frequently accessed properties are cached
- **Benchmarking**: Built-in performance tests available

Run benchmarks:

```bash
python -m pytest pytola/pdfcrypt/tests/test_benchmark.py --benchmark-only -v
```

## Security Features

- **Strong Password Validation**: Warns about weak passwords (< 6 characters)
- **128-bit AES Encryption**: Industry-standard encryption algorithm
- **Secure Resource Handling**: Automatic cleanup of file handles
- **Overwrite Protection**: Warns when target files already exist

## Testing

Run unit tests:

```bash
python -m pytest pytola/pdfcrypt/tests/test_pdfcrypt.py -v
```

Run all tests including benchmarks:

```bash
python -m pytest pytola/pdfcrypt/tests/ -v
```

## API Reference

### Main Functions

- `encrypt_pdf(filepath: Path, password: str) -> tuple[Path, Path | None]`
- `decrypt_pdf(filepath: Path, password: str) -> tuple[Path, Path | None]`
- `is_encrypted(filepath: Path) -> bool`
- `encrypt(password: str) -> None`
- `decrypt(password: str) -> None`

### Config

- `PDFCryptConfig`: Configuration dataclass with cached properties
- `conf`: Global configuration instance

### Helper Functions

- `_validate_password_strength(password: str) -> None`
- `_setup_pdf_writer(reader: pypdf.PdfReader) -> pypdf.PdfWriter`
- `_handle_output_file_conflict(filepath: Path) -> None`
- `_cleanup_resources(reader=None, writer=None) -> None`

## Requirements

- Python >= 3.8
- pypdf >= 3.0.0
- Standard library modules: argparse, logging, pathlib, json

## Contributing

1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Ensure all tests pass
5. Submit a pull request

## License

MIT License - see LICENSE file for details.

## Changelog

### v1.0.0

- Initial release
- Core encryption/decryption functionality
- Batch processing support
- Configuration persistence
- Comprehensive test suite
- Performance benchmarks
