//
//  CustomItemSubscriptionService.swift
//  SportsTime
//
//  CloudKit subscription service for real-time custom item updates
//

import Foundation
import CloudKit
import Combine

/// Manages CloudKit subscriptions for custom itinerary items on shared trips
actor CustomItemSubscriptionService {
    static let shared = CustomItemSubscriptionService()

    private let container: CKContainer
    private let publicDatabase: CKDatabase

    /// Publisher that emits trip IDs when their custom items change
    private let changeSubject = PassthroughSubject<UUID, Never>()
    var changePublisher: AnyPublisher<UUID, Never> {
        changeSubject.eraseToAnyPublisher()
    }

    /// Track which trip IDs have active subscriptions
    private var subscribedTripIds: Set<UUID> = []

    private init() {
        self.container = CKContainer(identifier: "iCloud.com.sportstime.app")
        self.publicDatabase = container.publicCloudDatabase
    }

    // MARK: - Subscription Management

    /// Subscribe to changes for a specific trip's custom items
    func subscribeToTrip(_ tripId: UUID) async throws {
        guard !subscribedTripIds.contains(tripId) else {
            print("📡 [Subscription] Already subscribed to trip: \(tripId)")
            return
        }

        let subscriptionID = "custom-items-\(tripId.uuidString)"

        // Check if subscription already exists
        do {
            _ = try await publicDatabase.subscription(for: subscriptionID)
            subscribedTripIds.insert(tripId)
            print("📡 [Subscription] Found existing subscription for trip: \(tripId)")
            return
        } catch let error as CKError where error.code == .unknownItem {
            // Subscription doesn't exist, create it
        } catch {
            print("📡 [Subscription] Error checking subscription: \(error)")
        }

        // Create subscription for this trip's custom items
        let predicate = NSPredicate(
            format: "%K == %@",
            CKCustomItineraryItem.tripIdKey,
            tripId.uuidString
        )

        let subscription = CKQuerySubscription(
            recordType: CKRecordType.customItineraryItem,
            predicate: predicate,
            subscriptionID: subscriptionID,
            options: [.firesOnRecordCreation, .firesOnRecordUpdate, .firesOnRecordDeletion]
        )

        // Configure notification
        let notificationInfo = CKSubscription.NotificationInfo()
        notificationInfo.shouldSendContentAvailable = true // Silent notification
        subscription.notificationInfo = notificationInfo

        do {
            try await publicDatabase.save(subscription)
            subscribedTripIds.insert(tripId)
            print("📡 [Subscription] Created subscription for trip: \(tripId)")
        } catch let error as CKError {
            print("📡 [Subscription] Failed to create subscription: \(error.code.rawValue) - \(error.localizedDescription)")
            throw error
        }
    }

    /// Unsubscribe from a specific trip's custom items
    func unsubscribeFromTrip(_ tripId: UUID) async throws {
        guard subscribedTripIds.contains(tripId) else { return }

        let subscriptionID = "custom-items-\(tripId.uuidString)"

        do {
            try await publicDatabase.deleteSubscription(withID: subscriptionID)
            subscribedTripIds.remove(tripId)
            print("📡 [Subscription] Removed subscription for trip: \(tripId)")
        } catch let error as CKError where error.code == .unknownItem {
            // Already deleted
            subscribedTripIds.remove(tripId)
        }
    }

    /// Subscribe to all trips that the user has access to (via polls)
    func subscribeToSharedTrips(tripIds: [UUID]) async {
        for tripId in tripIds {
            do {
                try await subscribeToTrip(tripId)
            } catch {
                print("📡 [Subscription] Failed to subscribe to trip \(tripId): \(error)")
            }
        }
    }

    // MARK: - Notification Handling

    /// Handle CloudKit notification - call this from AppDelegate/SceneDelegate
    func handleNotification(_ notification: CKNotification) {
        guard let queryNotification = notification as? CKQueryNotification,
              let subscriptionID = queryNotification.subscriptionID,
              subscriptionID.hasPrefix("custom-items-") else {
            return
        }

        // Extract trip ID from subscription ID
        let tripIdString = String(subscriptionID.dropFirst("custom-items-".count))
        guard let tripId = UUID(uuidString: tripIdString) else { return }

        print("📡 [Subscription] Received change notification for trip: \(tripId)")
        changeSubject.send(tripId)
    }

    /// Handle notification from userInfo dictionary (from push notification)
    nonisolated func handleRemoteNotification(userInfo: [AnyHashable: Any]) async {
        guard let notification = CKNotification(fromRemoteNotificationDictionary: userInfo) else {
            return
        }
        await handleNotification(notification)
    }

    // MARK: - Cleanup

    /// Remove all subscriptions (call on sign out or cleanup)
    func removeAllSubscriptions() async {
        for tripId in subscribedTripIds {
            try? await unsubscribeFromTrip(tripId)
        }
        subscribedTripIds.removeAll()
    }
}
