/**
 * NotificationContent.java
 * 
 * Data model for notification content following the project directive schema
 * Implements the canonical NotificationContent v1 structure
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

package org.timesafari.dailynotification;

import android.util.Log;
import java.util.UUID;

/**
 * Represents notification content with all required fields
 * 
 * This class follows the canonical schema defined in the project directive:
 * - id: string (uuid)
 * - title: string
 * - body: string (plain text; may include simple emoji)
 * - scheduledTime: epoch millis (client-local target)
 * - mediaUrl: string? (for future; must be mirrored to local path before use)
 * - fetchTime: epoch millis
 */
public class NotificationContent {
    
    private String id;
    private String title;
    private String body;
    private long scheduledTime;
    private String mediaUrl;
    private final long fetchedAt;     // When content was fetched (immutable)
    private long scheduledAt;         // When this instance was scheduled
    
    // Gson will try to deserialize this field, but we ignore it to keep fetchedAt immutable
    @SuppressWarnings("unused")
    private transient long fetchTime; // Legacy field for Gson compatibility (ignored)
    
    // Custom deserializer to handle fetchedAt field
    public static class NotificationContentDeserializer implements com.google.gson.JsonDeserializer<NotificationContent> {
        @Override
        public NotificationContent deserialize(com.google.gson.JsonElement json, java.lang.reflect.Type typeOfT, com.google.gson.JsonDeserializationContext context) throws com.google.gson.JsonParseException {
            com.google.gson.JsonObject jsonObject = json.getAsJsonObject();
            
            // Preserve original ID and fetchedAt from JSON
            String id = jsonObject.has("id") ? jsonObject.get("id").getAsString() : null;
            long fetchedAt = jsonObject.has("fetchedAt") ? jsonObject.get("fetchedAt").getAsLong() : System.currentTimeMillis();
            
            // Create instance with preserved fetchedAt
            NotificationContent content = new NotificationContent(id, fetchedAt);
            
            // Deserialize other fields
            if (jsonObject.has("title")) content.title = jsonObject.get("title").getAsString();
            if (jsonObject.has("body")) content.body = jsonObject.get("body").getAsString();
            if (jsonObject.has("scheduledTime")) content.scheduledTime = jsonObject.get("scheduledTime").getAsLong();
            if (jsonObject.has("mediaUrl")) content.mediaUrl = jsonObject.get("mediaUrl").getAsString();
            if (jsonObject.has("scheduledAt")) content.scheduledAt = jsonObject.get("scheduledAt").getAsLong();
            if (jsonObject.has("sound")) content.sound = jsonObject.get("sound").getAsBoolean();
            if (jsonObject.has("priority")) content.priority = jsonObject.get("priority").getAsString();
            if (jsonObject.has("url")) content.url = jsonObject.get("url").getAsString();
            
            // Reduced logging - only in debug builds
            // Log.d("NotificationContent", "Deserialized content with fetchedAt=" + content.fetchedAt + " (from constructor)");
            
            return content;
        }
    }
    private boolean sound;
    private String priority;
    private String url;
    
    /**
     * Default constructor with auto-generated UUID
     */
    public NotificationContent() {
        this.id = UUID.randomUUID().toString();
        this.fetchedAt = System.currentTimeMillis();
        this.scheduledAt = System.currentTimeMillis();
        this.sound = true;
        this.priority = "default";
        // Reduced logging to prevent log spam - only log first few instances
        // (Logging removed - too verbose when loading many notifications from storage)
    }
    
    /**
     * Package-private constructor for deserialization
     * Preserves original fetchedAt from storage
     * 
     * @param id Original notification ID
     * @param fetchedAt Original fetch timestamp
     */
    NotificationContent(String id, long fetchedAt) {
        this.id = id != null ? id : UUID.randomUUID().toString();
        this.fetchedAt = fetchedAt;
        this.scheduledAt = System.currentTimeMillis(); // Reset scheduledAt on load
        this.sound = true;
        this.priority = "default";
    }
    
    /**
     * Constructor with all required fields
     * 
     * @param title Notification title
     * @param body Notification body text
     * @param scheduledTime When to display the notification
     */
    public NotificationContent(String title, String body, long scheduledTime) {
        this();
        this.title = title;
        this.body = body;
        this.scheduledTime = scheduledTime;
    }
    
    // Getters and Setters
    
    /**
     * Get the unique identifier for this notification
     * 
     * @return UUID string
     */
    public String getId() {
        return id;
    }
    
    /**
     * Set the unique identifier for this notification
     * 
     * @param id UUID string
     */
    public void setId(String id) {
        this.id = id;
    }
    
    /**
     * Get the notification title
     * 
     * @return Title string
     */
    public String getTitle() {
        return title;
    }
    
    /**
     * Set the notification title
     * 
     * @param title Title string
     */
    public void setTitle(String title) {
        this.title = title;
    }
    
    /**
     * Get the notification body text
     * 
     * @return Body text string
     */
    public String getBody() {
        return body;
    }
    
    /**
     * Set the notification body text
     * 
     * @param body Body text string
     */
    public void setBody(String body) {
        this.body = body;
    }
    
    /**
     * Get the scheduled time for this notification
     * 
     * @return Timestamp in milliseconds
     */
    public long getScheduledTime() {
        return scheduledTime;
    }
    
    /**
     * Set the scheduled time for this notification
     * 
     * @param scheduledTime Timestamp in milliseconds
     */
    public void setScheduledTime(long scheduledTime) {
        this.scheduledTime = scheduledTime;
    }
    
    /**
     * Get the media URL (optional, for future use)
     * 
     * @return Media URL string or null
     */
    public String getMediaUrl() {
        return mediaUrl;
    }
    
    /**
     * Set the media URL (optional, for future use)
     * 
     * @param mediaUrl Media URL string or null
     */
    public void setMediaUrl(String mediaUrl) {
        this.mediaUrl = mediaUrl;
    }
    
    /**
     * Get the fetch time when content was retrieved (immutable)
     * 
     * @return Timestamp in milliseconds
     */
    public long getFetchedAt() {
        return fetchedAt;
    }
    
    /**
     * Get when this notification instance was scheduled
     * 
     * @return Timestamp in milliseconds
     */
    public long getScheduledAt() {
        return scheduledAt;
    }
    
    /**
     * Set when this notification instance was scheduled
     * 
     * @param scheduledAt Timestamp in milliseconds
     */
    public void setScheduledAt(long scheduledAt) {
        this.scheduledAt = scheduledAt;
    }
    
    /**
     * Check if sound should be played
     * 
     * @return true if sound is enabled
     */
    public boolean isSound() {
        return sound;
    }
    
    /**
     * Set whether sound should be played
     * 
     * @param sound true to enable sound
     */
    public void setSound(boolean sound) {
        this.sound = sound;
    }
    
    /**
     * Get the notification priority
     * 
     * @return Priority string (high, default, low)
     */
    public String getPriority() {
        return priority;
    }
    
    /**
     * Set the notification priority
     * 
     * @param priority Priority string (high, default, low)
     */
    public void setPriority(String priority) {
        this.priority = priority;
    }
    
    /**
     * Get the associated URL
     * 
     * @return URL string or null
     */
    public String getUrl() {
        return url;
    }
    
    /**
     * Set the associated URL
     * 
     * @param url URL string or null
     */
    public void setUrl(String url) {
        this.url = url;
    }
    
    /**
     * Check if this notification content is stale (older than 24 hours)
     * 
     * @return true if notification content is stale
     */
    public boolean isStale() {
        long currentTime = System.currentTimeMillis();
        long age = currentTime - fetchedAt;
        return age > 24 * 60 * 60 * 1000; // 24 hours in milliseconds
    }
    
    /**
     * Get the age of this notification content in milliseconds
     * 
     * @return Age in milliseconds
     */
    public long getAge() {
        return System.currentTimeMillis() - fetchedAt;
    }
    
    /**
     * Get the age since this notification was scheduled
     * 
     * @return Age in milliseconds
     */
    public long getScheduledAge() {
        return System.currentTimeMillis() - scheduledAt;
    }
    
    /**
     * Get the age of this notification in a human-readable format
     * 
     * @return Human-readable age string
     */
    public String getAgeString() {
        long age = getAge();
        long seconds = age / 1000;
        long minutes = seconds / 60;
        long hours = minutes / 60;
        long days = hours / 24;
        
        if (days > 0) {
            return days + " day" + (days == 1 ? "" : "s") + " ago";
        } else if (hours > 0) {
            return hours + " hour" + (hours == 1 ? "" : "s") + " ago";
        } else if (minutes > 0) {
            return minutes + " minute" + (minutes == 1 ? "" : "s") + " ago";
        } else {
            return "just now";
        }
    }
    
    /**
     * Check if this notification is ready to be displayed
     * 
     * @return true if notification should be displayed now
     */
    public boolean isReadyToDisplay() {
        return System.currentTimeMillis() >= scheduledTime;
    }
    
    /**
     * Get time until this notification should be displayed
     * 
     * @return Time in milliseconds until display
     */
    public long getTimeUntilDisplay() {
        return Math.max(0, scheduledTime - System.currentTimeMillis());
    }
    
    @Override
    public String toString() {
        return "NotificationContent{" +
                "id='" + id + '\'' +
                ", title='" + title + '\'' +
                ", body='" + body + '\'' +
                ", scheduledTime=" + scheduledTime +
                ", mediaUrl='" + mediaUrl + '\'' +
                ", fetchedAt=" + fetchedAt +
                ", scheduledAt=" + scheduledAt +
                ", sound=" + sound +
                ", priority='" + priority + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        NotificationContent that = (NotificationContent) o;
        return id.equals(that.id);
    }
    
    @Override
    public int hashCode() {
        return id.hashCode();
    }
}
