/**
 * NotificationContentDAO.swift
 * 
 * Data Access Object (DAO) for NotificationContent Core Data entity
 * Provides CRUD operations and query helpers for notification content
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 * @created 2025-12-08
 */

import Foundation
import CoreData

/**
 * Extension providing DAO methods for NotificationContent entity
 * 
 * This extension adds CRUD operations and query helpers to the
 * auto-generated NotificationContent Core Data class.
 */
extension NotificationContentEntity {
    
    // MARK: - Constants
    
    private static let TAG = "DNP-NOTIFICATION-CONTENT-DAO"
    
    // MARK: - Create/Insert Methods
    
    /**
     * Create a new NotificationContent entity in the given context
     * 
     * @param context Core Data managed object context
     * @param id Unique notification identifier
     * @param pluginVersion Plugin version string
     * @param timesafariDid TimeSafari device ID
     * @param notificationType Type of notification
     * @param title Notification title
     * @param body Notification body
     * @param scheduledTime Scheduled delivery time (Date)
     * @param timezone Timezone string
     * @param priority Notification priority (0-10)
     * @param vibrationEnabled Whether vibration is enabled
     * @param soundEnabled Whether sound is enabled
     * @param mediaUrl URL to media content
     * @param encryptedContent Encrypted content string
     * @param encryptionKeyId Encryption key identifier
     * @param ttlSeconds Time-to-live in seconds
     * @param deliveryStatus Current delivery status
     * @param deliveryAttempts Number of delivery attempts
     * @param metadata Additional metadata (JSON string)
     * @return Created NotificationContent entity
     */
    static func create(
        in context: NSManagedObjectContext,
        id: String,
        pluginVersion: String? = nil,
        timesafariDid: String? = nil,
        notificationType: String? = nil,
        title: String? = nil,
        body: String? = nil,
        scheduledTime: Date,
        timezone: String? = nil,
        priority: Int32 = 0,
        vibrationEnabled: Bool = false,
        soundEnabled: Bool = true,
        mediaUrl: String? = nil,
        encryptedContent: String? = nil,
        encryptionKeyId: String? = nil,
        ttlSeconds: Int64 = 604800, // 7 days default
        deliveryStatus: String? = nil,
        deliveryAttempts: Int32 = 0,
        metadata: String? = nil
    ) -> NotificationContentEntity {
        let entity = NotificationContentEntity(context: context)
        let now = Date()
        
        entity.id = id
        entity.pluginVersion = pluginVersion
        entity.timesafariDid = timesafariDid
        entity.notificationType = notificationType
        entity.title = title
        entity.body = body
        entity.scheduledTime = scheduledTime
        entity.timezone = timezone
        entity.priority = priority
        entity.vibrationEnabled = vibrationEnabled
        entity.soundEnabled = soundEnabled
        entity.mediaUrl = mediaUrl
        entity.encryptedContent = encryptedContent
        entity.encryptionKeyId = encryptionKeyId
        entity.createdAt = now
        entity.updatedAt = now
        entity.ttlSeconds = ttlSeconds
        entity.deliveryStatus = deliveryStatus
        entity.deliveryAttempts = deliveryAttempts
        entity.lastDeliveryAttempt = nil
        entity.userInteractionCount = 0
        entity.lastUserInteraction = nil
        entity.metadata = metadata
        
        print("\(Self.TAG): Created NotificationContent with id: \(id)")
        return entity
    }
    
    /**
     * Create from dictionary representation
     * 
     * @param context Core Data managed object context
     * @param dict Dictionary with notification data
     * @return Created NotificationContent entity or nil
     */
    static func create(
        in context: NSManagedObjectContext,
        from dict: [String: Any]
    ) -> NotificationContentEntity? {
        guard let id = dict["id"] as? String else {
            print("\(Self.TAG): Missing required 'id' field")
            return nil
        }
        
        // Convert scheduledTime from epoch milliseconds or Date
        let scheduledTime: Date
        if let timeMillis = dict["scheduledTime"] as? Int64 {
            scheduledTime = DailyNotificationDataConversions.dateFromEpochMillis(timeMillis)
        } else if let timeDate = dict["scheduledTime"] as? Date {
            scheduledTime = timeDate
        } else {
            print("\(Self.TAG): Missing or invalid 'scheduledTime' field")
            return nil
        }
        
        // Convert createdAt/updatedAt if present
        let createdAt: Date
        if let createdMillis = dict["createdAt"] as? Int64 {
            createdAt = DailyNotificationDataConversions.dateFromEpochMillis(createdMillis)
        } else if let createdDate = dict["createdAt"] as? Date {
            createdAt = createdDate
        } else {
            createdAt = Date()
        }
        
        let updatedAt: Date
        if let updatedMillis = dict["updatedAt"] as? Int64 {
            updatedAt = DailyNotificationDataConversions.dateFromEpochMillis(updatedMillis)
        } else if let updatedDate = dict["updatedAt"] as? Date {
            updatedAt = updatedDate
        } else {
            updatedAt = Date()
        }
        
        let entity = NotificationContentEntity(context: context)
        entity.id = id
        entity.pluginVersion = dict["pluginVersion"] as? String
        entity.timesafariDid = dict["timesafariDid"] as? String
        entity.notificationType = dict["notificationType"] as? String
        entity.title = dict["title"] as? String
        entity.body = dict["body"] as? String
        entity.scheduledTime = scheduledTime
        entity.timezone = dict["timezone"] as? String
        entity.priority = DailyNotificationDataConversions.int32FromInt(
            dict["priority"] as? Int ?? 0
        )
        entity.vibrationEnabled = dict["vibrationEnabled"] as? Bool ?? false
        entity.soundEnabled = dict["soundEnabled"] as? Bool ?? true
        entity.mediaUrl = dict["mediaUrl"] as? String
        entity.encryptedContent = dict["encryptedContent"] as? String
        entity.encryptionKeyId = dict["encryptionKeyId"] as? String
        entity.createdAt = createdAt
        entity.updatedAt = updatedAt
        entity.ttlSeconds = dict["ttlSeconds"] as? Int64 ?? 604800
        entity.deliveryStatus = dict["deliveryStatus"] as? String
        entity.deliveryAttempts = DailyNotificationDataConversions.int32FromInt(
            dict["deliveryAttempts"] as? Int ?? 0
        )
        if let lastAttemptMillis = dict["lastDeliveryAttempt"] as? Int64 {
            entity.lastDeliveryAttempt = DailyNotificationDataConversions.dateFromEpochMillis(lastAttemptMillis)
        }
        entity.userInteractionCount = DailyNotificationDataConversions.int32FromInt(
            dict["userInteractionCount"] as? Int ?? 0
        )
        if let lastInteractionMillis = dict["lastUserInteraction"] as? Int64 {
            entity.lastUserInteraction = DailyNotificationDataConversions.dateFromEpochMillis(lastInteractionMillis)
        }
        entity.metadata = dict["metadata"] as? String
        
        return entity
    }
    
    // MARK: - Read/Query Methods
    
    /**
     * Fetch NotificationContent by ID
     * 
     * @param context Core Data managed object context
     * @param id Notification ID
     * @return NotificationContent entity or nil
     */
    static func fetch(
        by id: String,
        in context: NSManagedObjectContext
    ) -> NotificationContentEntity? {
        let request: NSFetchRequest<NotificationContentEntity> = NotificationContentEntity.fetchRequest()
        request.predicate = NSPredicate(format: "id == %@", id)
        request.fetchLimit = 1
        
        do {
            let results = try context.fetch(request)
            return results.first
        } catch {
            print("\(Self.TAG): Error fetching by id: \(error.localizedDescription)")
            return nil
        }
    }
    
    /**
     * Fetch all NotificationContent entities
     * 
     * @param context Core Data managed object context
     * @return Array of NotificationContent entities
     */
    static func fetchAll(
        in context: NSManagedObjectContext
    ) -> [NotificationContentEntity] {
        let request: NSFetchRequest<NotificationContentEntity> = NotificationContentEntity.fetchRequest()
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error fetching all: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query by timesafariDid
     * 
     * @param context Core Data managed object context
     * @param timesafariDid TimeSafari device ID
     * @return Array of NotificationContent entities
     */
    static func query(
        by timesafariDid: String,
        in context: NSManagedObjectContext
    ) -> [NotificationContentEntity] {
        let request: NSFetchRequest<NotificationContentEntity> = NotificationContentEntity.fetchRequest()
        request.predicate = NSPredicate(format: "timesafariDid == %@", timesafariDid)
        request.sortDescriptors = [NSSortDescriptor(key: "scheduledTime", ascending: true)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by timesafariDid: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query by notificationType
     * 
     * @param context Core Data managed object context
     * @param notificationType Notification type string
     * @return Array of NotificationContent entities
     */
    static func queryByNotificationType(
        _ notificationType: String,
        in context: NSManagedObjectContext
    ) -> [NotificationContentEntity] {
        let request: NSFetchRequest<NotificationContentEntity> = NotificationContentEntity.fetchRequest()
        request.predicate = NSPredicate(format: "notificationType == %@", notificationType)
        request.sortDescriptors = [NSSortDescriptor(key: "scheduledTime", ascending: true)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by notificationType: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query by scheduledTime range
     * 
     * @param context Core Data managed object context
     * @param startDate Start date (inclusive)
     * @param endDate End date (inclusive)
     * @return Array of NotificationContent entities
     */
    static func query(
        scheduledTimeBetween startDate: Date,
        and endDate: Date,
        in context: NSManagedObjectContext
    ) -> [NotificationContentEntity] {
        let request: NSFetchRequest<NotificationContentEntity> = NotificationContentEntity.fetchRequest()
        request.predicate = NSPredicate(
            format: "scheduledTime >= %@ AND scheduledTime <= %@",
            startDate as NSDate,
            endDate as NSDate
        )
        request.sortDescriptors = [NSSortDescriptor(key: "scheduledTime", ascending: true)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by scheduledTime range: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query by deliveryStatus
     * 
     * @param context Core Data managed object context
     * @param deliveryStatus Delivery status string
     * @return Array of NotificationContent entities
     */
    static func queryByDeliveryStatus(
        _ deliveryStatus: String,
        in context: NSManagedObjectContext
    ) -> [NotificationContentEntity] {
        let request: NSFetchRequest<NotificationContentEntity> = NotificationContentEntity.fetchRequest()
        request.predicate = NSPredicate(format: "deliveryStatus == %@", deliveryStatus)
        request.sortDescriptors = [NSSortDescriptor(key: "scheduledTime", ascending: true)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by deliveryStatus: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query notifications ready for delivery (scheduledTime <= currentTime)
     * 
     * @param context Core Data managed object context
     * @param currentTime Current time for comparison
     * @return Array of NotificationContent entities
     */
    static func queryReadyForDelivery(
        currentTime: Date,
        in context: NSManagedObjectContext
    ) -> [NotificationContentEntity] {
        let request: NSFetchRequest<NotificationContentEntity> = NotificationContentEntity.fetchRequest()
        request.predicate = NSPredicate(format: "scheduledTime <= %@", currentTime as NSDate)
        request.sortDescriptors = [NSSortDescriptor(key: "scheduledTime", ascending: true)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying ready for delivery: \(error.localizedDescription)")
            return []
        }
    }
    
    // MARK: - Update Methods
    
    /**
     * Update this entity's updatedAt timestamp
     */
    func touch() {
        self.updatedAt = Date()
    }
    
    /**
     * Update delivery status and increment attempts
     * 
     * @param status New delivery status
     */
    func updateDeliveryStatus(_ status: String) {
        self.deliveryStatus = status
        self.deliveryAttempts += 1
        self.lastDeliveryAttempt = Date()
        self.touch()
    }
    
    /**
     * Record user interaction
     */
    func recordUserInteraction() {
        self.userInteractionCount += 1
        self.lastUserInteraction = Date()
        self.touch()
    }
    
    // MARK: - Delete Methods
    
    /**
     * Delete NotificationContent by ID
     * 
     * @param context Core Data managed object context
     * @param id Notification ID
     * @return true if deleted, false otherwise
     */
    static func delete(
        by id: String,
        in context: NSManagedObjectContext
    ) -> Bool {
        guard let entity = fetch(by: id, in: context) else {
            return false
        }
        
        context.delete(entity)
        
        do {
            try context.save()
            print("\(Self.TAG): Deleted NotificationContent with id: \(id)")
            return true
        } catch {
            print("\(Self.TAG): Error deleting: \(error.localizedDescription)")
            context.rollback()
            return false
        }
    }
    
    /**
     * Delete all NotificationContent entities
     * 
     * @param context Core Data managed object context
     * @return Number of entities deleted
     */
    static func deleteAll(
        in context: NSManagedObjectContext
    ) -> Int {
        let request: NSFetchRequest<NSFetchRequestResult> = NotificationContentEntity.fetchRequest()
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
        
        do {
            let result = try context.execute(deleteRequest) as? NSBatchDeleteResult
            try context.save()
            let count = result?.result as? Int ?? 0
            print("\(Self.TAG): Deleted \(count) NotificationContent entities")
            return count
        } catch {
            print("\(Self.TAG): Error deleting all: \(error.localizedDescription)")
            context.rollback()
            return 0
        }
    }
}

