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

import Foundation
import CoreData

/**
 * Extension providing DAO methods for NotificationDelivery entity
 * 
 * This extension adds CRUD operations and query helpers to the
 * auto-generated NotificationDelivery Core Data class.
 */
extension NotificationDelivery {
    
    // MARK: - Constants
    
    private static let TAG = "DNP-NOTIFICATION-DELIVERY-DAO"
    
    // MARK: - Create/Insert Methods
    
    /**
     * Create a new NotificationDelivery entity in the given context
     * 
     * @param context Core Data managed object context
     * @param id Unique delivery identifier
     * @param notificationId Associated notification content ID
     * @param notificationContent Associated NotificationContent entity
     * @param timesafariDid TimeSafari device ID
     * @param deliveryTimestamp When delivery occurred
     * @param deliveryStatus Delivery status string
     * @param deliveryMethod Delivery method string
     * @param deliveryAttemptNumber Attempt number (1-based)
     * @param deliveryDurationMs Duration of delivery in milliseconds
     * @param userInteractionType Type of user interaction (if any)
     * @param userInteractionTimestamp When user interacted
     * @param userInteractionDurationMs Duration of interaction in milliseconds
     * @param errorCode Error code (if delivery failed)
     * @param errorMessage Error message (if delivery failed)
     * @param deviceInfo Device information JSON string
     * @param networkInfo Network information JSON string
     * @param batteryLevel Battery level (0-100, -1 if unknown)
     * @param dozeModeActive Whether device was in doze mode
     * @param exactAlarmPermission Whether exact alarm permission granted
     * @param notificationPermission Whether notification permission granted
     * @param metadata Additional metadata (JSON string)
     * @return Created NotificationDelivery entity
     */
    static func create(
        in context: NSManagedObjectContext,
        id: String,
        notificationId: String,
        notificationContent: NotificationContentEntity? = nil,
        timesafariDid: String? = nil,
        deliveryTimestamp: Date,
        deliveryStatus: String? = nil,
        deliveryMethod: String? = nil,
        deliveryAttemptNumber: Int32 = 1,
        deliveryDurationMs: Int64 = 0,
        userInteractionType: String? = nil,
        userInteractionTimestamp: Date? = nil,
        userInteractionDurationMs: Int64 = 0,
        errorCode: String? = nil,
        errorMessage: String? = nil,
        deviceInfo: String? = nil,
        networkInfo: String? = nil,
        batteryLevel: Int32 = -1,
        dozeModeActive: Bool = false,
        exactAlarmPermission: Bool = false,
        notificationPermission: Bool = false,
        metadata: String? = nil
    ) -> NotificationDelivery {
        let entity = NotificationDelivery(context: context)
        
        entity.id = id
        entity.notificationId = notificationId
        entity.notificationContent = notificationContent
        entity.timesafariDid = timesafariDid
        entity.deliveryTimestamp = deliveryTimestamp
        entity.deliveryStatus = deliveryStatus
        entity.deliveryMethod = deliveryMethod
        entity.deliveryAttemptNumber = deliveryAttemptNumber
        entity.deliveryDurationMs = deliveryDurationMs
        entity.userInteractionType = userInteractionType
        entity.userInteractionTimestamp = userInteractionTimestamp
        entity.userInteractionDurationMs = userInteractionDurationMs
        entity.errorCode = errorCode
        entity.errorMessage = errorMessage
        entity.deviceInfo = deviceInfo
        entity.networkInfo = networkInfo
        entity.batteryLevel = batteryLevel
        entity.dozeModeActive = dozeModeActive
        entity.exactAlarmPermission = exactAlarmPermission
        entity.notificationPermission = notificationPermission
        entity.metadata = metadata
        
        print("\(Self.TAG): Created NotificationDelivery with id: \(id)")
        return entity
    }
    
    /**
     * Create from dictionary representation
     * 
     * @param context Core Data managed object context
     * @param dict Dictionary with delivery data
     * @param notificationContent Optional associated NotificationContent entity
     * @return Created NotificationDelivery entity or nil
     */
    static func create(
        in context: NSManagedObjectContext,
        from dict: [String: Any],
        notificationContent: NotificationContentEntity? = nil
    ) -> NotificationDelivery? {
        guard let id = dict["id"] as? String,
              let notificationId = dict["notificationId"] as? String else {
            print("\(Self.TAG): Missing required fields")
            return nil
        }
        
        // Convert deliveryTimestamp from epoch milliseconds or Date
        let deliveryTimestamp: Date
        if let timeMillis = dict["deliveryTimestamp"] as? Int64 {
            deliveryTimestamp = DailyNotificationDataConversions.dateFromEpochMillis(timeMillis)
        } else if let timeDate = dict["deliveryTimestamp"] as? Date {
            deliveryTimestamp = timeDate
        } else {
            print("\(Self.TAG): Missing or invalid 'deliveryTimestamp' field")
            return nil
        }
        
        // Convert userInteractionTimestamp if present
        let userInteractionTimestamp: Date?
        if let interactionMillis = dict["userInteractionTimestamp"] as? Int64 {
            userInteractionTimestamp = DailyNotificationDataConversions.dateFromEpochMillis(interactionMillis)
        } else if let interactionDate = dict["userInteractionTimestamp"] as? Date {
            userInteractionTimestamp = interactionDate
        } else {
            userInteractionTimestamp = nil
        }
        
        let entity = NotificationDelivery(context: context)
        entity.id = id
        entity.notificationId = notificationId
        entity.notificationContent = notificationContent
        entity.timesafariDid = dict["timesafariDid"] as? String
        entity.deliveryTimestamp = deliveryTimestamp
        entity.deliveryStatus = dict["deliveryStatus"] as? String
        entity.deliveryMethod = dict["deliveryMethod"] as? String
        entity.deliveryAttemptNumber = DailyNotificationDataConversions.int32FromInt(
            dict["deliveryAttemptNumber"] as? Int ?? 1
        )
        entity.deliveryDurationMs = dict["deliveryDurationMs"] as? Int64 ?? 0
        entity.userInteractionType = dict["userInteractionType"] as? String
        entity.userInteractionTimestamp = userInteractionTimestamp
        entity.userInteractionDurationMs = dict["userInteractionDurationMs"] as? Int64 ?? 0
        entity.errorCode = dict["errorCode"] as? String
        entity.errorMessage = dict["errorMessage"] as? String
        entity.deviceInfo = dict["deviceInfo"] as? String
        entity.networkInfo = dict["networkInfo"] as? String
        entity.batteryLevel = DailyNotificationDataConversions.int32FromInt(
            dict["batteryLevel"] as? Int ?? -1
        )
        entity.dozeModeActive = dict["dozeModeActive"] as? Bool ?? false
        entity.exactAlarmPermission = dict["exactAlarmPermission"] as? Bool ?? false
        entity.notificationPermission = dict["notificationPermission"] as? Bool ?? false
        entity.metadata = dict["metadata"] as? String
        
        return entity
    }
    
    // MARK: - Read/Query Methods
    
    /**
     * Fetch NotificationDelivery by ID
     * 
     * @param context Core Data managed object context
     * @param id Delivery ID
     * @return NotificationDelivery entity or nil
     */
    static func fetch(
        by id: String,
        in context: NSManagedObjectContext
    ) -> NotificationDelivery? {
        let request: NSFetchRequest<NotificationDelivery> = NotificationDelivery.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
        }
    }
    
    /**
     * Query by notificationId
     * 
     * @param context Core Data managed object context
     * @param notificationId Notification content ID
     * @return Array of NotificationDelivery entities
     */
    static func queryByNotificationId(
        _ notificationId: String,
        in context: NSManagedObjectContext
    ) -> [NotificationDelivery] {
        let request: NSFetchRequest<NotificationDelivery> = NotificationDelivery.fetchRequest()
        request.predicate = NSPredicate(format: "notificationId == %@", notificationId)
        request.sortDescriptors = [NSSortDescriptor(key: "deliveryTimestamp", ascending: false)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by notificationId: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query by deliveryTimestamp range
     * 
     * @param context Core Data managed object context
     * @param startDate Start date (inclusive)
     * @param endDate End date (inclusive)
     * @return Array of NotificationDelivery entities
     */
    static func query(
        deliveryTimestampBetween startDate: Date,
        and endDate: Date,
        in context: NSManagedObjectContext
    ) -> [NotificationDelivery] {
        let request: NSFetchRequest<NotificationDelivery> = NotificationDelivery.fetchRequest()
        request.predicate = NSPredicate(
            format: "deliveryTimestamp >= %@ AND deliveryTimestamp <= %@",
            startDate as NSDate,
            endDate as NSDate
        )
        request.sortDescriptors = [NSSortDescriptor(key: "deliveryTimestamp", ascending: false)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by deliveryTimestamp range: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query by deliveryStatus
     * 
     * @param context Core Data managed object context
     * @param deliveryStatus Delivery status string
     * @return Array of NotificationDelivery entities
     */
    static func queryByDeliveryStatus(
        _ deliveryStatus: String,
        in context: NSManagedObjectContext
    ) -> [NotificationDelivery] {
        let request: NSFetchRequest<NotificationDelivery> = NotificationDelivery.fetchRequest()
        request.predicate = NSPredicate(format: "deliveryStatus == %@", deliveryStatus)
        request.sortDescriptors = [NSSortDescriptor(key: "deliveryTimestamp", ascending: false)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by deliveryStatus: \(error.localizedDescription)")
            return []
        }
    }
    
    /**
     * Query by timesafariDid
     * 
     * @param context Core Data managed object context
     * @param timesafariDid TimeSafari device ID
     * @return Array of NotificationDelivery entities
     */
    static func queryByTimesafariDid(
        _ timesafariDid: String,
        in context: NSManagedObjectContext
    ) -> [NotificationDelivery] {
        let request: NSFetchRequest<NotificationDelivery> = NotificationDelivery.fetchRequest()
        request.predicate = NSPredicate(format: "timesafariDid == %@", timesafariDid)
        request.sortDescriptors = [NSSortDescriptor(key: "deliveryTimestamp", ascending: false)]
        
        do {
            return try context.fetch(request)
        } catch {
            print("\(Self.TAG): Error querying by timesafariDid: \(error.localizedDescription)")
            return []
        }
    }
    
    // MARK: - Update Methods
    
    /**
     * Update delivery status
     * 
     * @param status New delivery status
     */
    func updateDeliveryStatus(_ status: String) {
        self.deliveryStatus = status
    }
    
    /**
     * Record user interaction
     * 
     * @param interactionType Type of interaction
     * @param timestamp When interaction occurred
     * @param durationMs Duration of interaction in milliseconds
     */
    func recordUserInteraction(
        type: String,
        timestamp: Date,
        durationMs: Int64
    ) {
        self.userInteractionType = type
        self.userInteractionTimestamp = timestamp
        self.userInteractionDurationMs = durationMs
    }
    
    // MARK: - Delete Methods
    
    /**
     * Delete NotificationDelivery by ID
     * 
     * @param context Core Data managed object context
     * @param id Delivery 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 NotificationDelivery with id: \(id)")
            return true
        } catch {
            print("\(Self.TAG): Error deleting: \(error.localizedDescription)")
            context.rollback()
            return false
        }
    }
    
    /**
     * Delete all NotificationDelivery entities for a notification
     * 
     * @param context Core Data managed object context
     * @param notificationId Notification content ID
     * @return Number of entities deleted
     */
    static func deleteAll(
        for notificationId: String,
        in context: NSManagedObjectContext
    ) -> Int {
        let deliveries = queryByNotificationId(notificationId, in: context)
        let count = deliveries.count
        
        for delivery in deliveries {
            context.delete(delivery)
        }
        
        do {
            try context.save()
            print("\(Self.TAG): Deleted \(count) NotificationDelivery entities for notification: \(notificationId)")
            return count
        } catch {
            print("\(Self.TAG): Error deleting all: \(error.localizedDescription)")
            context.rollback()
            return 0
        }
    }
    
    /**
     * Delete all NotificationDelivery entities
     * 
     * @param context Core Data managed object context
     * @return Number of entities deleted
     */
    static func deleteAll(
        in context: NSManagedObjectContext
    ) -> Int {
        let request: NSFetchRequest<NSFetchRequestResult> = NotificationDelivery.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) NotificationDelivery entities")
            return count
        } catch {
            print("\(Self.TAG): Error deleting all: \(error.localizedDescription)")
            context.rollback()
            return 0
        }
    }
}

