# VPS Integration - Code Changes Reference

## File: VPSAPIClient.swift (NEW FILE)

Created a complete API client with these sections:

1. **Configuration & Initialization**
   - Singleton pattern
   - URLSession setup with appropriate timeouts
   - Base URL configuration

2. **Health Check**
   ```swift
   func checkHealth() async throws -> Bool
   ```

3. **Download Operations**
   ```swift
   func downloadChapter(...) async throws -> VPSDownloadResult
   ```
   - Progress tracking via `@Published` properties
   - Active download tracking

4. **Status Checking**
   ```swift
   func getChapterManifest(...) async throws -> VPSChapterManifest?
   func listDownloadedChapters(...) async throws -> [VPSChapterInfo]
   ```

5. **Image URLs**
   ```swift
   func getImageURL(...) -> String
   ```

6. **Management**
   ```swift
   func deleteChapter(...) async throws -> Bool
   func getStorageStats() async throws -> VPSStorageStats
   ```

---

## File: MangaDetailView.swift

### Change 1: Import VPS Client
```swift
// Added to MangaDetailView struct
@StateObject private var vpsClient = VPSAPIClient.shared
```

### Change 2: Add VPS Download Button to Toolbar
```swift
// In toolbar
Button {
    viewModel.showingVPSDownloadAll = true
} label: {
    Image(systemName: "icloud.and.arrow.down")
}
.disabled(viewModel.chapters.isEmpty)
```

### Change 3: Add VPS Download Alert
```swift
.alert("Descargar a VPS", isPresented: $viewModel.showingVPSDownloadAll) {
    Button("Cancelar", role: .cancel) { }
    Button("Últimos 10 a VPS") {
        Task {
            await viewModel.downloadLastChaptersToVPS(count: 10)
        }
    }
    Button("Todos a VPS") {
        Task {
            await viewModel.downloadAllChaptersToVPS()
        }
    }
} message: {
    Text("¿Cuántos capítulos quieres descargar al servidor VPS?")
}
```

### Change 4: Update ChapterRowView
```swift
struct ChapterRowView: View {
    // Added:
    let onVPSDownloadToggle: () async -> Void
    @ObservedObject var vpsClient = VPSAPIClient.shared
    @State private var isVPSDownloaded = false
    @State private var isVPSChecked = false
```

### Change 5: Add VPS Status Indicator in ChapterRowView Body
```swift
// VPS Download Button / Status
if isVPSChecked {
    if isVPSDownloaded {
        Image(systemName: "icloud.fill")
            .foregroundColor(.blue)
    } else {
        Button {
            Task {
                await onVPSDownloadToggle()
            }
        } label: {
            Image(systemName: "icloud.and.arrow.up")
                .foregroundColor(.blue)
        }
        .buttonStyle(.plain)
    }
}
```

### Change 6: Add VPS Progress Display
```swift
// Mostrar progreso de descarga VPS
if vpsClient.activeDownloads.contains("\(mangaSlug)-\(chapter.number)"), 
   let progress = vpsClient.downloadProgress["\(mangaSlug)-\(chapter.number)"] {
    HStack {
        Image(systemName: "icloud.and.arrow.down")
            .font(.caption2)
            .foregroundColor(.blue)
        
        ProgressView(value: progress)
            .progressViewStyle(.linear)
            .frame(maxWidth: 100)
        
        Text("VPS \(Int(progress * 100))%")
            .font(.caption2)
            .foregroundColor(.blue)
    }
}
```

### Change 7: Add VPS Status Check Function
```swift
private func checkVPSStatus() async {
    do {
        let manifest = try await vpsClient.getChapterManifest(
            mangaSlug: mangaSlug,
            chapterNumber: chapter.number
        )
        isVPSDownloaded = manifest != nil
        isVPSChecked = true
    } catch {
        isVPSDownloaded = false
        isVPSChecked = true
    }
}
```

### Change 8: Update chaptersList to Pass VPS Callback
```swift
ChapterRowView(
    chapter: chapter,
    mangaSlug: manga.slug,
    onTap: {
        viewModel.selectedChapter = chapter
    },
    onDownloadToggle: {
        await viewModel.downloadChapter(chapter)
    },
    onVPSDownloadToggle: {  // NEW
        await viewModel.downloadChapterToVPS(chapter)
    }
)
```

### Change 9: ViewModel Additions
```swift
// New Published Property
@Published var showingVPSDownloadAll = false

// New Dependency
private let vpsClient = VPSAPIClient.shared

// New Methods
func downloadChapterToVPS(_ chapter: Chapter) async {
    do {
        let imageUrls = try await scraper.scrapeChapterImages(chapterSlug: chapter.slug)
        let result = try await vpsClient.downloadChapter(
            mangaSlug: manga.slug,
            chapterNumber: chapter.number,
            chapterSlug: chapter.slug,
            imageUrls: imageUrls
        )
        // Handle result and show notification
    } catch {
        // Handle error
    }
}

func downloadAllChaptersToVPS() async { /* ... */ }
func downloadLastChaptersToVPS(count: Int) async { /* ... */ }
```

---

## File: ReaderView.swift

### Change 1: Add VPS Client
```swift
// Added to ReaderView struct
@ObservedObject private var vpsClient = VPSAPIClient.shared
```

### Change 2: Update PageView for VPS Support
```swift
struct PageView: View {
    // Added:
    @ObservedObject var vpsClient = VPSAPIClient.shared
    @State private var useVPS = false
    
    var body: some View {
        // ...
        if let localURL = StorageService.shared.getImageURL(...) {
            // Load from local cache
        } else if useVPS {
            // Load from VPS
            let vpsImageURL = vpsClient.getImageURL(
                mangaSlug: mangaSlug,
                chapterNumber: chapterNumber,
                pageIndex: page.index + 1
            )
            AsyncImage(url: URL(string: vpsImageURL)) { /* ... */ }
        } else {
            // Load from original URL
            fallbackImage
        }
        // ...
        .task {
            // Check if VPS has this chapter
            if let manifest = try? await vpsClient.getChapterManifest(...) {
                useVPS = true
            }
        }
    }
    
    private var fallbackImage: some View { /* ... */ }
}
```

### Change 3: Update ReaderViewModel
```swift
// New Published Property
@Published var isVPSDownloaded = false

// New Dependency
private let vpsClient = VPSAPIClient.shared

// Updated loadPages()
func loadPages() async {
    // 1. Check VPS first
    if let vpsManifest = try await vpsClient.getChapterManifest(...) {
        // Load from VPS
        isVPSDownloaded = true
    }
    // 2. Then local storage
    else if let downloadedChapter = storage.getDownloadedChapter(...) {
        // Load from local
        isDownloaded = true
    }
    // 3. Finally scrape
    else {
        // Scrape from original
    }
}
```

### Change 4: Update Reader Footer
```swift
// Page indicator section
if viewModel.isVPSDownloaded {
    Label("VPS", systemImage: "icloud.fill")
        .font(.caption)
        .foregroundColor(.blue)
}

if viewModel.isDownloaded {
    Label("Local", systemImage: "checkmark.circle.fill")
        .font(.caption)
        .foregroundColor(.green)
}
```

---

## Data Models (in VPSAPIClient.swift)

### VPSDownloadResult
```swift
struct VPSDownloadResult {
    let success: Bool
    let alreadyDownloaded: Bool
    let manifest: VPSChapterManifest?
    let downloaded: Int?
    let failed: Int?
}
```

### VPSChapterManifest
```swift
struct VPSChapterManifest: Codable {
    let mangaSlug: String
    let chapterNumber: Int
    let totalPages: Int
    let downloadedPages: Int
    let failedPages: Int
    let downloadDate: String
    let totalSize: Int
    let images: [VPSImageInfo]
}
```

### VPSChapterInfo
```swift
struct VPSChapterInfo: Codable {
    let chapterNumber: Int
    let downloadDate: String
    let totalPages: Int
    let downloadedPages: Int
    let totalSize: Int
    let totalSizeMB: String
}
```

### VPSStorageStats
```swift
struct VPSStorageStats: Codable {
    let totalMangas: Int
    let totalChapters: Int
    let totalSize: Int
    let totalSizeMB: String
    let totalSizeFormatted: String
    let mangaDetails: [VPSMangaDetail]
}
```

---

## Priority Order for Image Loading

1. **Local Device Storage** (fastest, offline)
2. **VPS Storage** (fast, online)
3. **Original URL** (slowest, may fail)

This ensures best performance and reliability.

---

## Error Handling Pattern

All VPS operations follow this pattern:

```swift
do {
    let result = try await vpsClient.someMethod(...)
    // Handle success
} catch {
    // Handle error - show user notification
    notificationMessage = "Error: \(error.localizedDescription)"
    showDownloadNotification = true
}
```

---

## Progress Tracking Pattern

For downloads:

```swift
// Track active downloads
vpsClient.activeDownloads.contains("downloadId")

// Get progress
vpsClient.downloadProgress["downloadId"]

// Display in UI
ProgressView(value: progress)
Text("\(Int(progress * 100))%")
```

