# API Configuration for MangaReader iOS App

## Overview

This directory contains the API configuration for connecting the iOS app to the VPS backend. The configuration is centralized in `APIConfig.swift` and includes all necessary settings for API communication.

## Files

- **APIConfig.swift**: Main configuration file with all API settings, endpoints, and helper methods
- **APIConfigExample.swift**: Comprehensive usage examples and demonstrations
- **README.md** (this file): Documentation and usage guide

## Current Configuration

### Server Connection
- **Server URL**: `https://gitea.cbcren.online`
- **Port**: `3001`
- **Full Base URL**: `https://gitea.cbcren.online:3001`
- **API Version**: `v1`
- **API Base Path**: `https://gitea.cbcren.online:3001/api/v1`

### Timeouts
- **Default Request Timeout**: `30.0` seconds (for regular API calls)
- **Resource Download Timeout**: `300.0` seconds (5 minutes, for large downloads)

### Retry Policy
- **Max Retries**: `3` attempts
- **Base Retry Delay**: `1.0` second (with exponential backoff)

### Cache Configuration
- **Max Memory Usage**: `100` cached responses
- **Cache Expiry**: `300.0` seconds (5 minutes)

## Usage

### Basic URL Construction

```swift
// Method 1: Use the helper function
let url = APIConfig.url(for: "manga/popular")
// Result: "https://gitea.cbcren.online:3001/manga/popular"

// Method 2: Get a URL object
if let urlObj = APIConfig.urlObject(for: "manga/popular") {
    var request = URLRequest(url: urlObj)
    // Make request...
}

// Method 3: Use predefined endpoints
let endpoint = APIConfig.Endpoints.download(mangaSlug: "one-piece", chapterNumber: 1089)
// Result: "https://gitea.cbcren.online:3001/api/v1/download/one-piece/1089"
```

### URLSession Configuration

```swift
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = APIConfig.defaultTimeout
configuration.timeoutIntervalForResource = APIConfig.downloadTimeout
let session = URLSession(configuration: configuration)
```

### URLRequest with Headers

```swift
var request = URLRequest(url: url)
request.timeoutInterval = APIConfig.defaultTimeout

// Add common headers
for (key, value) in APIConfig.commonHeaders {
    request.setValue(value, forHTTPHeaderField: key)
}

// Add authentication if needed
if let token = authToken {
    let authHeaders = APIConfig.authHeader(token: token)
    for (key, value) in authHeaders {
        request.setValue(value, forHTTPHeaderField: key)
    }
}
```

## Available Endpoints

### Download Endpoints

```swift
// Request chapter download
APIConfig.Endpoints.download(mangaSlug: "one-piece", chapterNumber: 1089)

// Check if chapter is downloaded
APIConfig.Endpoints.checkDownloaded(mangaSlug: "one-piece", chapterNumber: 1089)

// List all downloaded chapters for a manga
APIConfig.Endpoints.listChapters(mangaSlug: "one-piece")

// Get specific image from chapter
APIConfig.Endpoints.getImage(mangaSlug: "one-piece", chapterNumber: 1089, pageIndex: 0)

// Delete a chapter
APIConfig.Endpoints.deleteChapter(mangaSlug: "one-piece", chapterNumber: 1089)
```

### Server Endpoints

```swift
// Get storage statistics
APIConfig.Endpoints.storageStats()

// Health check
APIConfig.Endpoints.health()
```

## Environment Configuration

The configuration includes presets for different environments:

### Development
```swift
APIConfig.development
// - serverURL: "http://192.168.1.100"
// - port: 3001
// - timeout: 60.0s
// - logging: true
```

### Staging
```swift
APIConfig.staging
// - serverURL: "https://staging.cbcren.online"
// - port: 3001
// - timeout: 30.0s
// - logging: true
```

### Production (Current)
```swift
APIConfig.production
// - serverURL: "https://gitea.cbcren.online"
// - port: 3001
// - timeout: 30.0s
// - logging: false
```

### Testing (Debug Only)
```swift
#if DEBUG
APIConfig.testing
// - serverURL: "http://localhost:3001"
// - port: 3001
// - timeout: 5.0s
// - logging: true
#endif
```

## Changing the Server URL

To change the API server URL, modify the `serverURL` property in `APIConfig.swift`:

```swift
// In APIConfig.swift, line 37
static let serverURL = "https://gitea.cbcren.online" // Change this
```

For environment-specific URLs, use compile-time conditionals:

```swift
#if DEBUG
static let serverURL = "http://192.168.1.100"  // Local development
#else
static let serverURL = "https://gitea.cbcren.online"  // Production
#endif
```

## Error Codes

The API defines specific error codes for different scenarios:

```swift
APIConfig.ErrorCodes.chapterNotFound           // 40401
APIConfig.ErrorCodes.chapterAlreadyDownloaded  // 40901
APIConfig.ErrorCodes.storageLimitExceeded      // 50701
APIConfig.ErrorCodes.invalidImageFormat        // 42201
APIConfig.ErrorCodes.downloadFailed            // 50001
```

## Validation

The configuration includes a validation method:

```swift
if APIConfig.isValid {
    print("Configuration is valid")
} else {
    print("Configuration is invalid")
}
```

This checks:
- Server URL is not empty
- Port is in valid range (1-65535)
- Timeout values are positive
- Retry count is non-negative

## Debug Support

In debug builds, you can print the current configuration:

```swift
#if DEBUG
APIConfig.printConfiguration()
#endif
```

This outputs:
```
=== API Configuration ===
Server URL: https://gitea.cbcren.online
Port: 3001
Base URL: https://gitea.cbcren.online:3001
API Version: v1
Default Timeout: 30.0s
Download Timeout: 300.0s
Max Retries: 3
Logging Enabled: false
Cache Enabled: true
=========================
```

## Best Practices

1. **Always use predefined endpoints** when available instead of manually constructing URLs
2. **Use appropriate timeouts** - `defaultTimeout` for regular calls, `downloadTimeout` for large downloads
3. **Validate configuration** on app startup
4. **Use the helper methods** (`url()`, `urlObject()`) for URL construction
5. **Include common headers** in all requests
6. **Handle specific error codes** defined in `APIConfig.ErrorCodes`
7. **Enable logging only in debug builds** for security

## Example: Making an API Call

```swift
func fetchPopularManga() async throws -> [Manga] {
    // Construct URL
    guard let url = APIConfig.urlObject(for: "manga/popular") else {
        throw APIError.invalidURL
    }

    // Create request
    var request = URLRequest(url: url)
    request.timeoutInterval = APIConfig.defaultTimeout

    // Add headers
    for (key, value) in APIConfig.commonHeaders {
        request.setValue(value, forHTTPHeaderField: key)
    }

    // Make request
    let (data, response) = try await URLSession.shared.data(for: request)

    // Validate response
    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw APIError.requestFailed
    }

    // Decode response
    let mangas = try JSONDecoder().decode([Manga].self, from: data)
    return mangas
}
```

## Example: Downloading with Retry

```swift
func downloadChapterWithRetry(
    mangaSlug: String,
    chapterNumber: Int
) async throws -> Data {
    let endpoint = APIConfig.Endpoints.download(
        mangaSlug: mangaSlug,
        chapterNumber: chapterNumber
    )

    return try await fetchWithRetry(endpoint: endpoint, retryCount: 0)
}

func fetchWithRetry(endpoint: String, retryCount: Int) async throws -> Data {
    guard let url = URL(string: endpoint),
          retryCount < APIConfig.maxRetries else {
        throw APIError.retryLimitExceeded
    }

    var request = URLRequest(url: url)
    request.timeoutInterval = APIConfig.downloadTimeout

    do {
        let (data, response) = try await URLSession.shared.data(for: request)

        if let httpResponse = response as? HTTPURLResponse,
           httpResponse.statusCode == 200 {
            return data
        } else {
            throw APIError.requestFailed
        }
    } catch {
        // Calculate exponential backoff delay
        let delay = APIConfig.baseRetryDelay * pow(2.0, Double(retryCount))
        try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))

        return try await fetchWithRetry(endpoint: endpoint, retryCount: retryCount + 1)
    }
}
```

## Troubleshooting

### Connection Issues

1. **Verify server URL**: Check that `serverURL` is correct and accessible
2. **Check port**: Ensure `port` matches the backend server configuration
3. **Test connectivity**: Use the health endpoint: `APIConfig.Endpoints.health()`
4. **Enable logging**: Set `loggingEnabled = true` to see request details

### Timeout Issues

1. **For regular API calls**: Use `APIConfig.defaultTimeout` (30 seconds)
2. **For large downloads**: Use `APIConfig.downloadTimeout` (300 seconds)
3. **Slow networks**: Increase timeout values if needed

### SSL Certificate Issues

If using HTTPS with a self-signed certificate:
1. Add the certificate to the app's bundle
2. Configure URLSession to trust the certificate
3. Or use HTTP for development (not recommended for production)

## Migration Notes

When migrating from the old configuration:

1. Replace hardcoded URLs with `APIConfig.url(for:)` or predefined endpoints
2. Use `APIConfig.commonHeaders` instead of manually setting headers
3. Replace hardcoded timeouts with `APIConfig.defaultTimeout` or `APIConfig.downloadTimeout`
4. Add validation on app startup with `APIConfig.isValid`
5. Use specific error codes from `APIConfig.ErrorCodes`

## Additional Resources

- See `APIConfigExample.swift` for more comprehensive examples
- Check the backend API documentation for available endpoints
- Review the iOS app's Services directory for integration examples
