import Foundation
import CoreSpotlight
import CoreData
import UIKit
import UniformTypeIdentifiers

class SpotlightSearchManager {
    static let shared = SpotlightSearchManager()

    private var lastFullIndexTime: Date?
    private let minimumIndexInterval: TimeInterval = 300 // 5 minutes between full re-indexes

    private init() {}

    // MARK: - Permission and Setup

    /// Check if Spotlight indexing is available
    func isSpotlightAvailable() -> Bool {
        return CSSearchableIndex.isIndexingAvailable()
    }

    /// Initialize Spotlight indexing with proper permissions
    func initializeSpotlightIndexing() {
        guard isSpotlightAvailable() else {
            print("Spotlight indexing is not available on this device")
            return
        }

        // Clear any existing index first, then reindex
        clearAllIndexedLinks()

        // Index all links after a short delay to ensure cleanup is complete
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            self.indexAllLinks()
        }
    }

    // MARK: - Indexing

    /// Index all links in Spotlight search
    func indexAllLinks() {
        // Rate limit full indexing to avoid overwhelming the system
        if let lastIndex = lastFullIndexTime,
           Date().timeIntervalSince(lastIndex) < minimumIndexInterval {
            print("Skipping full index - too soon since last index")
            return
        }

        let context = PersistenceController.shared.container.viewContext
        let request: NSFetchRequest<Link> = Link.fetchRequest()

        do {
            let links = try context.fetch(request)
            let searchableItems = links.compactMap { createSearchableItem(for: $0) }

            CSSearchableIndex.default().indexSearchableItems(searchableItems) { error in
                if let error = error {
                    print("Failed to index links: \(error.localizedDescription)")
                } else {
                    print("Successfully indexed \(searchableItems.count) links")
                    self.lastFullIndexTime = Date()
                }
            }
        } catch {
            print("Failed to fetch links for indexing: \(error.localizedDescription)")
        }
    }

    /// Index a single link
    func indexLink(_ link: Link) {
        guard let searchableItem = createSearchableItem(for: link) else { return }

        CSSearchableIndex.default().indexSearchableItems([searchableItem]) { error in
            if let error = error {
                print("Failed to index link \(link.alias): \(error.localizedDescription)")
            } else {
                print("Successfully indexed link: \(link.alias)")
            }
        }
    }

    /// Remove a link from Spotlight index
    func removeLink(withAlias alias: String) {
        CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: [alias]) { error in
            if let error = error {
                print("Failed to remove link \(alias) from index: \(error.localizedDescription)")
            } else {
                print("Successfully removed link \(alias) from index")
            }
        }
    }

    /// Clear all indexed links
    func clearAllIndexedLinks() {
        CSSearchableIndex.default().deleteAllSearchableItems { error in
            if let error = error {
                print("Failed to clear all indexed links: \(error.localizedDescription)")
            } else {
                print("Successfully cleared all indexed links")
            }
        }
    }

    // MARK: - Debug and Testing

    /// Get status of indexed items (for debugging)
    func getIndexedItemsStatus(completion: @escaping (Int) -> Void) {
        var query = CSSearchQuery(queryString: "contentType == 'public.url'", attributes: ["kMDItemTitle"])
        query = CSSearchQuery(queryString: "*", attributes: nil)

        var itemCount = 0

        query.foundItemsHandler = { items in
            itemCount += items.count
        }

        query.completionHandler = { error in
            DispatchQueue.main.async {
                if let error = error {
                    print("Error querying indexed items: \(error.localizedDescription)")
                    completion(0)
                } else {
                    completion(itemCount)
                }
            }
        }

        query.start()
    }

    // MARK: - Private Methods

    private func createSearchableItem(for link: Link) -> CSSearchableItem? {
        let attributeSet = CSSearchableItemAttributeSet(contentType: UTType.url)

        // Set basic attributes
        attributeSet.title = "Heygo: \(link.alias)"

        // Add URL if it's a link type
        if link.linkTypeEnum == .link, let urlString = link.originalURL, let url = URL(string: urlString) {
            attributeSet.contentURL = url
            // Add URL as part of the content description for search
            if let description = link.linkDescription, !description.isEmpty {
                attributeSet.contentDescription = "\(description) - \(urlString)"
            } else {
                attributeSet.contentDescription = urlString
            }
        } else {
            // For non-link types, just use the description
            attributeSet.contentDescription = link.linkDescription ?? ""
        }

        // Add text content for custom/template types
        if let text = link.text, !text.isEmpty {
            attributeSet.textContent = text
        }

        // Add comprehensive keywords for better search
        var keywords = [String]()

        // Add the alias as primary keyword
        keywords.append(link.alias)

        // Add individual characters of alias for prefix matching
        let aliasChars = Array(link.alias.lowercased())
        for i in 1...aliasChars.count {
            let prefix = String(aliasChars[0..<i])
            keywords.append(prefix)
        }

        // Add tag names
        let tagNames = link.sortedTags.map { $0.name }
        keywords.append(contentsOf: tagNames)

        // Add app identifier for filtering
        keywords.append("heygo")
        keywords.append("link")

        // Add link type as keyword
        keywords.append(link.linkTypeEnum.displayName.lowercased())

        attributeSet.keywords = keywords

        // Add click count as a ranking signal
        attributeSet.rankingHint = NSNumber(value: link.clickCount)

        // Add creation and modification dates
        attributeSet.contentCreationDate = link.createdAt
        attributeSet.contentModificationDate = link.updatedAt

        // Set icon/thumbnail based on link type (using SF Symbols would be better, but text works)
        switch link.linkTypeEnum {
        case .link:
            // For links, we could set a specific thumbnail or leave it to the system
            break
        case .custom:
            // For custom content
            break
        case .template:
            // For templates
            break
        }

        // Create searchable item with unique identifier
        let item = CSSearchableItem(uniqueIdentifier: link.alias, domainIdentifier: "heygo.links", attributeSet: attributeSet)

        // Set expiration date (optional - remove after 30 days of no updates)
        item.expirationDate = Calendar.current.date(byAdding: .day, value: 30, to: link.updatedAt)

        return item
    }
}

// MARK: - Search Result Handling

extension SpotlightSearchManager {

    /// Handle when user selects a spotlight search result
    static func handleSpotlightSearchSelection(userActivity: NSUserActivity) -> String? {
        guard userActivity.activityType == CSSearchableItemActionType,
              let uniqueIdentifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String else {
            return nil
        }

        return uniqueIdentifier // This is the link alias
    }

    /// Open link and record click
    static func openLinkFromSpotlight(alias: String, linkViewModel: LinkViewModel) {
        // Find the link by alias
        let context = PersistenceController.shared.container.viewContext
        let request: NSFetchRequest<Link> = Link.fetchRequest()
        request.predicate = NSPredicate(format: "alias == %@", alias)
        request.fetchLimit = 1

        do {
            let links = try context.fetch(request)
            guard let link = links.first else {
                print("Link with alias '\(alias)' not found")
                return
            }

            // Record the click
            linkViewModel.recordClick(for: link)

            // Handle different link types
            switch link.linkTypeEnum {
            case .link:
                if let urlString = link.originalURL, let url = URL(string: urlString) {
                    // Open URL in default browser
                    if UIApplication.shared.canOpenURL(url) {
                        UIApplication.shared.open(url, options: [:]) { success in
                            if !success {
                                print("Failed to open URL: \(url)")
                            }
                        }
                    }
                }
            case .template:
                // For template links, check if they have parameters
                if let urlString = link.originalURL, link.hasParametersInURL() {
                    // If template has parameters, show the app to handle parameter input
                    NotificationCenter.default.post(
                        name: NSNotification.Name("ShowTemplateParameterInput"),
                        object: nil,
                        userInfo: ["link": link]
                    )
                } else if let urlString = link.originalURL, let url = URL(string: urlString) {
                    // If no parameters, treat as regular link
                    if UIApplication.shared.canOpenURL(url) {
                        UIApplication.shared.open(url, options: [:]) { success in
                            if !success {
                                print("Failed to open template URL: \(url)")
                            }
                        }
                    }
                }
            case .custom:
                // For custom types, show the content in the app
                NotificationCenter.default.post(
                    name: NSNotification.Name("ShowLinkContent"),
                    object: nil,
                    userInfo: ["link": link]
                )
            }

        } catch {
            print("Failed to fetch link: \(error.localizedDescription)")
        }
    }
}
