/**
 * DailyNotificationJWTManager.java
 * 
 * Android JWT Manager for TimeSafari authentication enhancement
 * Extends existing ETagManager infrastructure with DID-based JWT authentication
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 * @created 2025-10-03 06:53:30 UTC
 */

package org.timesafari.dailynotification;

import android.util.Log;
import android.content.Context;

import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;

/**
 * Manages JWT authentication for TimeSafari integration
 * 
 * This class extends the existing ETagManager infrastructure by adding:
 * - DID-based JWT token generation
 * - Automatic JWT header injection into HTTP requests
 * - JWT token expiration management
 * - Integration with existing DailyNotificationETagManager
 * 
 * Phase 1 Implementation: Extends existing DailyNotificationETagManager.java
 */
public class DailyNotificationJWTManager {
    
    // MARK: - Constants
    
    private static final String TAG = "DailyNotificationJWTManager";
    
    // JWT Headers
    private static final String HEADER_AUTHORIZATION = "Authorization";
    private static final String HEADER_CONTENT_TYPE = "Content-Type";
    
    // JWT Configuration
    private static final int DEFAULT_JWT_EXPIRATION_SECONDS = 60;
    
    // JWT Algorithm (simplified for Phase 1)
    private static final String ALGORITHM = "HS256";
    
    // MARK: - Properties
    
    private final DailyNotificationStorage storage;
    private final DailyNotificationETagManager eTagManager;
    
    // Current authentication state
    private String currentActiveDid;
    private String currentJWTToken;
    private long jwtExpirationTime;
    
    // Configuration
    private int jwtExpirationSeconds;
    
    // MARK: - Initialization
    
    /**
     * Constructor
     * 
     * @param storage Storage instance for persistence
     * @param eTagManager ETagManager instance for HTTP enhancements
     */
    public DailyNotificationJWTManager(DailyNotificationStorage storage, DailyNotificationETagManager eTagManager) {
        this.storage = storage;
        this.eTagManager = eTagManager;
        this.jwtExpirationSeconds = DEFAULT_JWT_EXPIRATION_SECONDS;
        
        Log.d(TAG, "JWTManager initialized with ETagManager integration");
    }
    
    // MARK: - ActiveDid Management
    
    /**
     * Set the active DID for authentication
     * 
     * @param activeDid The DID to use for JWT generation
     */
    public void setActiveDid(String activeDid) {
        setActiveDid(activeDid, DEFAULT_JWT_EXPIRATION_SECONDS);
    }
    
    /**
     * Set the active DID for authentication with custom expiration
     * 
     * @param activeDid The DID to use for JWT generation
     * @param expirationSeconds JWT expiration time in seconds
     */
    public void setActiveDid(String activeDid, int expirationSeconds) {
        try {
            Log.d(TAG, "Setting activeDid: " + activeDid + " with " + expirationSeconds + "s expiration");
            
            this.currentActiveDid = activeDid;
            this.jwtExpirationSeconds = expirationSeconds;
            
            // Generate new JWT token immediately
            generateAndCacheJWT();
            
            Log.i(TAG, "ActiveDid set successfully");
            
        } catch (Exception e) {
            Log.e(TAG, "Error setting activeDid", e);
            throw new RuntimeException("Failed to set activeDid", e);
        }
    }
    
    /**
     * Get the current active DID
     * 
     * @return Current active DID or null if not set
     */
    public String getCurrentActiveDid() {
        return currentActiveDid;
    }
    
    /**
     * Check if we have a valid active DID and JWT token
     * 
     * @return true if authentication is ready
     */
    public boolean isAuthenticated() {
        return currentActiveDid != null && 
               currentJWTToken != null && 
               !isTokenExpired();
    }
    
    // MARK: - JWT Token Management
    
    /**
     * Generate JWT token for current activeDid
     * 
     * @param expiresInSeconds Expiration time in seconds
     * @return Generated JWT token
     */
    public String generateJWTForActiveDid(String activeDid, int expiresInSeconds) {
        try {
            Log.d(TAG, "Generating JWT for activeDid: " + activeDid);
            
            long currentTime = System.currentTimeMillis() / 1000;
            
            // Create JWT payload
            Map<String, Object> payload = new HashMap<>();
            payload.put("exp", currentTime + expiresInSeconds);
            payload.put("iat", currentTime);
            payload.put("iss", activeDid);
            payload.put("aud", "timesafari.notifications");
            payload.put("sub", activeDid);
            
            // Generate JWT token (simplified implementation for Phase 1)
            String jwt = signWithDID(payload, activeDid);
            
            Log.d(TAG, "JWT generated successfully");
            return jwt;
            
        } catch (Exception e) {
            Log.e(TAG, "Error generating JWT", e);
            throw new RuntimeException("Failed to generate JWT", e);
        }
    }
    
    /**
     * Generate and cache JWT token for current activeDid
     */
    private void generateAndCacheJWT() {
        if (currentActiveDid == null) {
            Log.w(TAG, "Cannot generate JWT: no activeDid set");
            return;
        }
        
        try {
            currentJWTToken = generateJWTForActiveDid(currentActiveDid, jwtExpirationSeconds);
            jwtExpirationTime = System.currentTimeMillis() + (jwtExpirationSeconds * 1000L);
            
            Log.d(TAG, "JWT cached successfully, expires at: " + jwtExpirationTime);
            
        } catch (Exception e) {
            Log.e(TAG, "Error caching JWT", e);
            throw new RuntimeException("Failed to cache JWT", e);
        }
    }
    
    /**
     * Check if current JWT token is expired
     * 
     * @return true if token is expired
     */
    private boolean isTokenExpired() {
        return currentJWTToken == null || System.currentTimeMillis() >= jwtExpirationTime;
    }
    
    /**
     * Refresh JWT token if needed
     */
    public void refreshJWTIfNeeded() {
        if (isTokenExpired()) {
            Log.d(TAG, "JWT token expired, refreshing");
            generateAndCacheJWT();
        }
    }
    
    /**
     * Get current valid JWT token (refreshes if needed)
     * 
     * @return Current JWT token
     */
    public String getCurrentJWTToken() {
        refreshJWTIfNeeded();
        return currentJWTToken;
    }
    
    // MARK: - HTTP Client Enhancement
    
    /**
     * Enhance HTTP client with JWT authentication headers
     * 
     * Extends existing DailyNotificationETagManager connection creation
     * 
     * @param connection HTTP connection to enhance
     * @param activeDid DID for authentication (optional, uses current if null)
     */
    public void enhanceHttpClientWithJWT(HttpURLConnection connection, String activeDid) {
        try {
            // Set activeDid if provided
            if (activeDid != null && !activeDid.equals(currentActiveDid)) {
                setActiveDid(activeDid);
            }
            
            // Ensure we have a valid token
            if (!isAuthenticated()) {
                throw new IllegalStateException("No valid authentication available");
            }
            
            // Add JWT Authorization header
            String jwt = getCurrentJWTToken();
            connection.setRequestProperty(HEADER_AUTHORIZATION, "Bearer " + jwt);
            
            // Set JSON content type for API requests
            connection.setRequestProperty(HEADER_CONTENT_TYPE, "application/json");
            
            Log.d(TAG, "HTTP client enhanced with JWT authentication");
            
        } catch (Exception e) {
            Log.e(TAG, "Error enhancing HTTP client with JWT", e);
            throw new RuntimeException("Failed to enhance HTTP client", e);
        }
    }
    
    /**
     * Enhance HTTP client with JWT authentication for current activeDid
     * 
     * @param connection HTTP connection to enhance
     */
    public void enhanceHttpClientWithJWT(HttpURLConnection connection) {
        enhanceHttpClientWithJWT(connection, null);
    }
    
    // MARK: - JWT Signing (Simplified for Phase 1)
    
    /**
     * Sign JWT payload with DID (simplified implementation)
     * 
     * Phase 1: Basic implementation using DID-based signing
     * Later phases: Integrate with proper DID cryptography
     * 
     * @param payload JWT payload
     * @param did DID for signing
     * @return Signed JWT token
     */
    private String signWithDID(Map<String, Object> payload, String did) {
        try {
            // Phase 1: Simplified JWT implementation
            // In production, this would use proper DID + cryptography libraries
            
            // Create JWT header
            Map<String, Object> header = new HashMap<>();
            header.put("alg", ALGORITHM);
            header.put("typ", "JWT");
            
            // Encode header and payload
            StringBuilder jwtBuilder = new StringBuilder();
            
            // Header
            jwtBuilder.append(base64UrlEncode(mapToJson(header)));
            jwtBuilder.append(".");
            
            // Payload  
            jwtBuilder.append(base64UrlEncode(mapToJson(payload)));
            jwtBuilder.append(".");
            
            // Signature (simplified - would use proper DID signing)
            String signature = createSignature(jwtBuilder.toString(), did);
            jwtBuilder.append(signature);
            
            String jwt = jwtBuilder.toString();
            Log.d(TAG, "JWT signed successfully (length: " + jwt.length() + ")");
            
            return jwt;
            
        } catch (Exception e) {
            Log.e(TAG, "Error signing JWT", e);
            throw new RuntimeException("Failed to sign JWT", e);
        }
    }
    
    /**
     * Create JWT signature (simplified for Phase 1)
     * 
     * @param data Data to sign
     * @param did DID for signature
     * @return Base64-encoded signature
     */
    private String createSignature(String data, String did) throws Exception {
        // Phase 1: Simplified signature using DID hash
        // Production would use proper DID cryptographic signing
        
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest((data + ":" + did).getBytes(StandardCharsets.UTF_8));
        
        return base64UrlEncode(hash);
    }
    
    /**
     * Convert map to JSON string (simplified)
     */
    private String mapToJson(Map<String, Object> map) {
        StringBuilder json = new StringBuilder("{");
        boolean first = true;
        
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (!first) json.append(",");
            json.append("\"").append(entry.getKey()).append("\":");
            
            Object value = entry.getValue();
            if (value instanceof String) {
                json.append("\"").append(value).append("\"");
            } else {
                json.append(value);
            }
            
            first = false;
        }
        
        json.append("}");
        return json.toString();
    }
    
    /**
     * Base64 URL-safe encoding
     */
    private String base64UrlEncode(byte[] data) {
        return Base64.getUrlEncoder()
            .withoutPadding()
            .encodeToString(data);
    }
    
    /**
     * Base64 URL-safe encoding for strings
     */
    private String base64UrlEncode(String data) {
        return base64UrlEncode(data.getBytes(StandardCharsets.UTF_8));
    }
    
    // MARK: - Testing and Debugging
    
    /**
     * Get current JWT token info for debugging
     * 
     * @return Token information
     */
    public String getTokenDebugInfo() {
        return String.format(
            "JWT Token Info - ActiveDID: %s, HasToken: %s, Expired: %s, ExpiresAt: %d",
            currentActiveDid,
            currentJWTToken != null,
            isTokenExpired(),
            jwtExpirationTime
        );
    }
    
    /**
     * Clear authentication state
     */
    public void clearAuthentication() {
        try {
            Log.d(TAG, "Clearing authentication state");
            
            currentActiveDid = null;
            currentJWTToken = null;
            jwtExpirationTime = 0;
            
            Log.i(TAG, "Authentication state cleared");
            
        } catch (Exception e) {
            Log.e(TAG, "Error clearing authentication", e);
        }
    }
}
