/**
 * Offline Mode TypeScript Types
 *
 * Type definitions for asset preloading, offline download, and PWA functionality.
 */

// Asset variant types matching backend model
export type AssetVariantType =
  | 'thumbnail'
  | 'preview'
  | 'webp'
  | 'mp4_low'
  | 'mp4_high'
  | 'original';

export type AssetType = 'image' | 'video' | 'audio' | 'transition' | 'other';

// Preload job status
export type PreloadJobStatus =
  | 'queued'
  | 'downloading'
  | 'completed'
  | 'error'
  | 'paused';

// Download job for tracking individual asset downloads
export interface PreloadJob {
  id: string;
  assetId: string;
  url: string;
  filename: string;
  progress: number;
  status: PreloadJobStatus;
  bytesLoaded: number;
  totalBytes: number;
  pageId?: string;
  variantType?: AssetVariantType;
  assetType?: AssetType;
  error?: string;
  addedAt: number;
  startedAt?: number;
  completedAt?: number;
}

// Project offline status
export type ProjectOfflineStatus =
  | 'not_downloaded'
  | 'downloading'
  | 'downloaded'
  | 'outdated'
  | 'error';

// Offline project metadata
export interface OfflineProject {
  id: string;
  slug: string;
  name: string;
  status: ProjectOfflineStatus;
  totalAssets: number;
  downloadedAssets: number;
  totalSizeBytes: number;
  downloadedSizeBytes: number;
  lastSyncedAt?: number;
  version?: string;
}

// Offline asset stored in IndexedDB
export interface OfflineAsset {
  id: string;
  projectId: string;
  url: string;
  filename: string;
  variantType: AssetVariantType;
  assetType: AssetType;
  mimeType: string;
  sizeBytes: number;
  blob: Blob;
  downloadedAt: number;
}

// Download queue item for persistence
export interface DownloadQueueItem {
  id: string;
  projectId: string;
  assetId: string;
  url: string;
  filename: string;
  status: PreloadJobStatus;
  priority: number;
  retryCount: number;
  bytesLoaded: number;
  totalBytes: number;
  addedAt: number;
  lastAttemptAt?: number;
  error?: string;
}

// Network information
export interface NetworkInfo {
  isOnline: boolean;
  effectiveType?: 'slow-2g' | '2g' | '3g' | '4g';
  downlink?: number; // Mbps
  rtt?: number; // ms
  saveData?: boolean;
}

// Storage quota info
export interface StorageQuotaInfo {
  usage: number;
  quota: number;
  percentUsed: number;
  available: number;
  canStore: (bytes: number) => boolean;
}

// Offline manifest from backend
export interface OfflineManifest {
  version: string;
  projectId: string;
  projectSlug: string;
  assets: ManifestAsset[];
  totalSizeBytes: number;
  generatedAt: number;
}

export interface ManifestAsset {
  id: string;
  url: string;
  filename: string;
  variantType: AssetVariantType;
  assetType: AssetType;
  mimeType: string;
  sizeBytes: number;
  pageIds: string[];
}

// Preload orchestrator state
export interface PreloadState {
  isActive: boolean;
  currentPageId: string | null;
  queuedAssets: string[];
  loadingAssets: string[];
  completedAssets: string[];
  failedAssets: string[];
  totalProgress: number;
}

// Neighbor graph for preloading
export interface NeighborGraph {
  // Map from pageId to array of connected pageIds with distance
  connections: Map<string, Array<{ pageId: string; distance: number }>>;
  // Get neighbors within a certain depth
  getNeighbors: (pageId: string, maxDepth: number) => string[];
  // Get all assets for a set of pages
  getAssetsForPages: (pageIds: string[]) => string[];
}

// Event payloads for DownloadEventBus
export interface PreloadStartEvent {
  jobId: string;
  assetId: string;
  url: string;
}

export interface PreloadProgressEvent {
  jobId: string;
  progress: number;
  bytesLoaded: number;
  totalBytes: number;
}

export interface PreloadCompleteEvent {
  jobId: string;
  assetId: string;
}

export interface PreloadErrorEvent {
  jobId: string;
  assetId: string;
  error: string;
}

export interface ProjectDownloadProgressEvent {
  projectId: string;
  progress: number;
  downloadedAssets: number;
  totalAssets: number;
  downloadedBytes: number;
  totalBytes: number;
}

export interface ProjectDownloadCompleteEvent {
  projectId: string;
}
