//
//  DataManager+ChannelNotificationSettings.swift
//  Yattee
//
//  Channel notification settings operations for DataManager.
//

import Foundation
import SwiftData

extension DataManager {
    // MARK: - Channel Notification Settings

    /// Sets notification preferences for a channel.
    /// Creates the settings record if it doesn't exist.
    /// - Parameters:
    ///   - enabled: Whether notifications should be enabled.
    ///   - channelID: The channel ID to set preferences for.
    func setNotificationsEnabled(_ enabled: Bool, for channelID: String) {
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            predicate: #Predicate { $0.channelID == channelID }
        )

        do {
            let existing = try modelContext.fetch(descriptor)

            let settings: ChannelNotificationSettings
            if let existingSettings = existing.first {
                // Update existing record
                existingSettings.setNotificationsEnabled(enabled)
                settings = existingSettings
            } else {
                // Derive source info from the matching subscription
                let sub = subscription(for: channelID)
                settings = ChannelNotificationSettings(
                    channelID: channelID,
                    notificationsEnabled: enabled,
                    sourceRawValue: sub?.sourceRawValue ?? "global",
                    instanceURLString: sub?.instanceURLString,
                    globalProvider: sub?.providerName
                )
                modelContext.insert(settings)
            }
            save()

            // Queue for CloudKit sync
            cloudKitSync?.queueChannelNotificationSettingsSave(settings)
        } catch {
            LoggingService.shared.logCloudKitError("Failed to set notification settings", error: error)
        }
    }

    /// Gets notification preferences for a channel.
    /// - Parameter channelID: The channel ID to get preferences for.
    /// - Returns: Whether notifications are enabled. Defaults to false if no settings exist.
    func notificationsEnabled(for channelID: String) -> Bool {
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            predicate: #Predicate { $0.channelID == channelID }
        )

        do {
            let results = try modelContext.fetch(descriptor)
            return results.first?.notificationsEnabled ?? false
        } catch {
            LoggingService.shared.logCloudKitError("Failed to fetch notification settings", error: error)
            return false
        }
    }

    /// Gets the notification settings record for a channel.
    /// - Parameter channelID: The channel ID to get settings for.
    /// - Returns: The settings record, or nil if none exists.
    func channelNotificationSettings(for channelID: String) -> ChannelNotificationSettings? {
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            predicate: #Predicate { $0.channelID == channelID }
        )

        do {
            return try modelContext.fetch(descriptor).first
        } catch {
            LoggingService.shared.logCloudKitError("Failed to fetch notification settings", error: error)
            return nil
        }
    }

    /// Gets all channel IDs with notifications enabled.
    /// Used for background refresh to determine which channels to check.
    /// - Returns: Array of channel IDs with notifications enabled.
    func channelIDsWithNotificationsEnabled() -> [String] {
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            predicate: #Predicate { $0.notificationsEnabled == true }
        )

        do {
            let results = try modelContext.fetch(descriptor)
            return results.map { $0.channelID }
        } catch {
            LoggingService.shared.logCloudKitError("Failed to fetch channels with notifications enabled", error: error)
            return []
        }
    }

    /// Gets all channel notification settings.
    /// - Returns: Array of all notification settings records.
    func allChannelNotificationSettings() -> [ChannelNotificationSettings] {
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            sortBy: [SortDescriptor(\.channelID)]
        )

        do {
            return try modelContext.fetch(descriptor)
        } catch {
            LoggingService.shared.logCloudKitError("Failed to fetch all notification settings", error: error)
            return []
        }
    }

    /// Gets all notification settings matching a channel ID. The same ID can
    /// exist under multiple source scopes.
    func allChannelNotificationSettings(forChannelID channelID: String) -> [ChannelNotificationSettings] {
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            predicate: #Predicate { $0.channelID == channelID }
        )
        return (try? modelContext.fetch(descriptor)) ?? []
    }

    /// Deletes a single notification settings record without queueing a
    /// CloudKit deletion. Used by CloudKitSyncEngine when applying remote deletions.
    func deleteChannelNotificationSettings(_ settings: ChannelNotificationSettings) {
        modelContext.delete(settings)
        save()
    }

    /// Deletes notification settings for a channel.
    /// - Parameter channelID: The channel ID to delete settings for.
    func deleteNotificationSettings(for channelID: String) {
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            predicate: #Predicate { $0.channelID == channelID }
        )

        do {
            let results = try modelContext.fetch(descriptor)
            guard !results.isEmpty else { return }

            // Capture scopes before deleting
            let scopes = results.map {
                SourceScope.from(
                    sourceRawValue: $0.sourceRawValue,
                    globalProvider: $0.globalProvider,
                    instanceURLString: $0.instanceURLString,
                    externalExtractor: nil
                )
            }

            for settings in results {
                modelContext.delete(settings)
            }
            save()

            // Queue scoped CloudKit deletions
            for scope in scopes {
                cloudKitSync?.queueChannelNotificationSettingsDelete(channelID: channelID, scope: scope)
            }
        } catch {
            LoggingService.shared.logCloudKitError("Failed to delete notification settings", error: error)
        }
    }

    /// Inserts or updates notification settings from CloudKit sync.
    /// - Parameter settings: The notification settings to upsert.
    func upsertChannelNotificationSettings(_ settings: ChannelNotificationSettings) {
        let channelID = settings.channelID
        let descriptor = FetchDescriptor<ChannelNotificationSettings>(
            predicate: #Predicate { $0.channelID == channelID }
        )

        do {
            let existing = try modelContext.fetch(descriptor)

            if let existingSettings = existing.first {
                // Update if incoming is newer
                if settings.updatedAt > existingSettings.updatedAt {
                    existingSettings.notificationsEnabled = settings.notificationsEnabled
                    existingSettings.updatedAt = settings.updatedAt
                    existingSettings.sourceRawValue = settings.sourceRawValue
                    existingSettings.instanceURLString = settings.instanceURLString
                    existingSettings.globalProvider = settings.globalProvider
                }
            } else {
                // Insert new record
                modelContext.insert(settings)
            }
            save()
        } catch {
            LoggingService.shared.logCloudKitError("Failed to upsert notification settings", error: error)
        }
    }
}
