/**
 * NativeNotificationContentFetcher.java
 * 
 * Service Provider Interface (SPI) for native content fetchers.
 * 
 * This interface is part of the Integration Point Refactor (PR1) that allows
 * host apps to provide their own content fetching logic without hardcoding
 * TimeSafari-specific code in the plugin.
 * 
 * Host apps implement this interface in native code (Kotlin/Java) and register
 * it with the plugin. The plugin calls this interface from background workers
 * (WorkManager) to fetch notification content.
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

package org.timesafari.dailynotification;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * Native content fetcher interface for host app implementations
 * 
 * This interface enables the plugin to call host app's native code for
 * fetching notification content. This is the ONLY path used by background
 * workers, as JavaScript bridges are unreliable in background contexts.
 * 
 * Implementation Requirements:
 * - Must be thread-safe (may be called from WorkManager background threads)
 * - Must complete within reasonable time (plugin enforces timeout)
 * - Should return empty list on failure rather than throwing exceptions
 * - Should handle errors gracefully and log for debugging
 * 
 * Example Implementation:
 * <pre>
 * class TimeSafariNativeFetcher implements NativeNotificationContentFetcher {
 *     private final TimeSafariApi api;
 *     private final TokenProvider tokenProvider;
 *     
 *     @Override
 *     public CompletableFuture<List<NotificationContent>> fetchContent(
 *             FetchContext context) {
 *         return CompletableFuture.supplyAsync(() -> {
 *             try {
 *                 String jwt = tokenProvider.freshToken();
 *                 // Fetch from TimeSafari API
 *                 // Convert to NotificationContent[]
 *                 return notificationContents;
 *             } catch (Exception e) {
 *                 Log.e("Fetcher", "Fetch failed", e);
 *                 return Collections.emptyList();
 *             }
 *         });
 *     }
 * }
 * </pre>
 */
public interface NativeNotificationContentFetcher {
    
    /**
     * Fetch notification content from external source
     * 
     * This method is called by the plugin when:
     * - Background fetch work is triggered (WorkManager)
     * - Prefetch is scheduled before notification time
     * - Manual refresh is requested (if native fetcher enabled)
     * 
     * The plugin will:
     * - Enforce a timeout (default 30 seconds, configurable via SchedulingPolicy)
     * - Handle empty lists gracefully (no notifications scheduled)
     * - Log errors for debugging
     * - Retry on failure based on SchedulingPolicy
     * 
     * @param context Context about why fetch was triggered, including
     *                trigger type, scheduled time, and optional metadata
     * @return CompletableFuture that resolves to list of NotificationContent.
     *         Empty list indicates no content available (not an error).
     *         The future should complete exceptionally only on unrecoverable errors.
     */
    @NonNull
    CompletableFuture<List<NotificationContent>> fetchContent(@NonNull FetchContext context);
    
    /**
     * Optional: Configure the native fetcher with API credentials and settings
     * 
     * <p>This method is called by the plugin when {@code configureNativeFetcher} is invoked
     * from TypeScript. It provides a cross-platform mechanism for passing configuration
     * from the JavaScript layer to native code without using platform-specific storage
     * mechanisms.</p>
     * 
     * <p><b>When to implement:</b></p>
     * <ul>
     *   <li>Your fetcher needs API credentials (URL, authentication tokens, etc.)</li>
     *   <li>Configuration should come from TypeScript/JavaScript code (e.g., from app config)</li>
     *   <li>You want to avoid hardcoding credentials in native code</li>
     * </ul>
     * 
     * <p><b>When to skip (use default no-op):</b></p>
     * <ul>
     *   <li>Your fetcher gets credentials from platform-specific storage (SharedPreferences, Keychain, etc.)</li>
     *   <li>Your fetcher has hardcoded test credentials</li>
     *   <li>Configuration is handled internally and doesn't need external input</li>
     * </ul>
     * 
     * <p><b>Thread Safety:</b> This method may be called from any thread. Implementations
     * must be thread-safe if storing configuration in instance variables.</p>
     * 
     * <p><b>Implementation Pattern:</b></p>
     * <pre>{@code
     * private volatile String apiBaseUrl;
     * private volatile String activeDid;
     * private volatile String jwtSecret;
     * 
     * @Override
     * public void configure(String apiBaseUrl, String activeDid, String jwtSecret) {
     *     this.apiBaseUrl = apiBaseUrl;
     *     this.activeDid = activeDid;
     *     this.jwtSecret = jwtSecret;
     *     Log.i(TAG, "Fetcher configured with API: " + apiBaseUrl);
     * }
     * }</pre>
     * 
     * @param apiBaseUrl Base URL for API server. Examples:
     *                   - Android emulator: "http://10.0.2.2:3000" (maps to host localhost:3000)
     *                   - iOS simulator: "http://localhost:3000"
     *                   - Production: "https://api.timesafari.com"
     * @param activeDid Active DID (Decentralized Identifier) for authentication.
     *                  Used as the JWT issuer/subject. Format: "did:ethr:0x..."
     * @param jwtToken Pre-generated JWT token (ES256K signed) from TypeScript.
     *                 This token is generated in the host app using TimeSafari's
     *                 {@code createEndorserJwtForKey()} function. The native fetcher
     *                 should use this token directly in the Authorization header as
     *                 "Bearer {jwtToken}". No JWT generation or signing is needed in Java.
     * 
     * @see DailyNotificationPlugin#configureNativeFetcher(PluginCall)
     */
    default void configure(String apiBaseUrl, String activeDid, String jwtToken) {
        // Default no-op implementation - fetchers that need config can override
        // This allows fetchers that don't need TypeScript-provided configuration
        // to ignore this method without implementing an empty body.
    }

    /**
     * Optional overload: distinct JWT strings for background use (e.g. one per day slot).
     * Persisted when {@code persistToken} is true; host fetchers (e.g. TimeSafari) should choose
     * which entry to use per fetch (e.g. day index modulo pool size).
     * Default delegates to {@link #configure(String, String, String)} so existing fetchers stay compatible.
     *
     * @param jwtTokenPool validated list (max length 128), or null if the host omitted the pool or sent an empty array
     */
    default void configure(
            String apiBaseUrl,
            String activeDid,
            String jwtToken,
            @Nullable List<String> jwtTokenPool) {
        configure(apiBaseUrl, activeDid, jwtToken);
    }
}

