"""Data models for the disk reorganizer""" from dataclasses import dataclass, field from pathlib import Path from datetime import datetime from typing import Optional @dataclass class FileRecord: """Core file record with all metadata""" path: Path size: int modified_time: float created_time: float disk_label: str checksum: Optional[str] = None status: str = 'indexed' # indexed, planned, moved, verified category: Optional[str] = None duplicate_of: Optional[str] = None def to_dict(self) -> dict: """Convert to dictionary for serialization""" return { 'path': str(self.path), 'size': self.size, 'modified_time': self.modified_time, 'created_time': self.created_time, 'disk_label': self.disk_label, 'checksum': self.checksum, 'status': self.status, 'category': self.category, 'duplicate_of': self.duplicate_of } @dataclass class OperationRecord: """Record of a migration operation""" source_path: Path target_path: Path operation_type: str # move, copy, hardlink, symlink size: int = 0 status: str = 'pending' # pending, in_progress, completed, failed error: Optional[str] = None executed_at: Optional[datetime] = None verified: bool = False def to_dict(self) -> dict: """Convert to dictionary for serialization""" return { 'source_path': str(self.source_path), 'target_path': str(self.target_path), 'operation_type': self.operation_type, 'size': self.size, 'status': self.status, 'error': self.error, 'executed_at': self.executed_at.isoformat() if self.executed_at else None, 'verified': self.verified } @dataclass class DiskInfo: """Information about a disk/volume""" name: str device: str mount_point: Path total_size: int used_size: int free_size: int fs_type: str @property def usage_percent(self) -> float: """Calculate usage percentage""" if self.total_size == 0: return 0.0 return (self.used_size / self.total_size) * 100 @dataclass class MigrationPlan: """Complete migration plan""" target_disk: str destination_disks: list[str] operations: list[OperationRecord] total_size: int file_count: int created_at: datetime = field(default_factory=datetime.now) def to_dict(self) -> dict: """Convert to dictionary for serialization""" return { 'target_disk': self.target_disk, 'destination_disks': self.destination_disks, 'operations': [op.to_dict() for op in self.operations], 'total_size': self.total_size, 'file_count': self.file_count, 'created_at': self.created_at.isoformat() } @dataclass class ProcessingStats: """Statistics for processing operations""" files_processed: int = 0 bytes_processed: int = 0 files_succeeded: int = 0 files_failed: int = 0 start_time: datetime = field(default_factory=datetime.now) @property def elapsed_seconds(self) -> float: """Calculate elapsed time in seconds""" return (datetime.now() - self.start_time).total_seconds() @property def files_per_second(self) -> float: """Calculate processing rate""" elapsed = self.elapsed_seconds return self.files_processed / elapsed if elapsed > 0 else 0.0 @property def bytes_per_second(self) -> float: """Calculate throughput""" elapsed = self.elapsed_seconds return self.bytes_processed / elapsed if elapsed > 0 else 0.0