import Foundation
import WatchConnectivity
import CoreImage
import CoreImage.CIFilterBuiltins
import UIKit
import Bedrock

/// Manages WatchConnectivity session and sends card data to Apple Watch
@MainActor
final class WatchConnectivityService: NSObject {
    static let shared = WatchConnectivityService()
    
    private var session: WCSession?
    private var isActivated = false
    private var pendingCards: [BusinessCard]?
    
    private override init() {
        super.init()
        if WCSession.isSupported() {
            session = WCSession.default
            session?.delegate = self
            session?.activate()
            Design.debugLog("WatchConnectivity: Session activating...")
        } else {
            Design.debugLog("WatchConnectivity: Not supported on this device")
        }
    }
    
    /// Syncs the given cards to the paired Apple Watch
    func syncCards(_ cards: [BusinessCard]) {
        // If not yet activated, store cards to send after activation
        guard isActivated else {
            Design.debugLog("WatchConnectivity: Session not ready, queuing \(cards.count) cards")
            pendingCards = cards
            return
        }
        
        guard let session = session else {
            Design.debugLog("WatchConnectivity: No session available")
            return
        }
        
        // In DEBUG, isWatchAppInstalled may be false even when running from Xcode
        // So we only require isPaired and isReachable or just try to send anyway
        #if DEBUG
        guard session.isPaired else {
            Design.debugLog("WatchConnectivity: Watch not paired")
            return
        }
        Design.debugLog("WatchConnectivity: DEBUG mode - paired: \(session.isPaired), installed: \(session.isWatchAppInstalled), reachable: \(session.isReachable)")
        #else
        guard session.isPaired, session.isWatchAppInstalled else {
            Design.debugLog("WatchConnectivity: Watch not available (paired: \(session.isPaired), installed: \(session.isWatchAppInstalled))")
            return
        }
        #endif
        
        sendCardsToWatch(cards)
    }
    
    private func sendCardsToWatch(_ cards: [BusinessCard]) {
        guard let session = session else { return }
        
        Design.debugLog("WatchConnectivity: Syncing \(cards.count) cards to Watch (reachable: \(session.isReachable))")
        
        let syncableCards = cards.map { card in
            createSyncableCard(from: card)
        }
        
        do {
            let encoded = try JSONEncoder().encode(syncableCards)
            let message: [String: Any] = ["cards": encoded]
            
            // ALWAYS update application context - this persists and will be available
            // when watch app launches, even if not currently reachable
            do {
                try session.updateApplicationContext(message)
                Design.debugLog("WatchConnectivity: Updated application context with \(encoded.count) bytes")
            } catch {
                Design.debugLog("WatchConnectivity: updateApplicationContext failed: \(error)")
            }
            
            // Also try immediate delivery if reachable
            if session.isReachable {
                session.sendMessage(message, replyHandler: nil) { error in
                    Task { @MainActor in
                        Design.debugLog("WatchConnectivity: sendMessage failed: \(error)")
                    }
                }
                Design.debugLog("WatchConnectivity: Also sent via sendMessage (reachable)")
            }
        } catch {
            Design.debugLog("WatchConnectivity: ERROR - Failed to encode: \(error)")
        }
    }
    
    fileprivate func handleActivation() {
        isActivated = true
        
        Design.debugLog("WatchConnectivity: Activation complete - paired: \(session?.isPaired ?? false), installed: \(session?.isWatchAppInstalled ?? false), reachable: \(session?.isReachable ?? false)")
        
        // Send any pending cards that were queued before activation
        if let cards = pendingCards {
            Design.debugLog("WatchConnectivity: Sending \(cards.count) queued cards after activation")
            pendingCards = nil
            syncCards(cards)
        }
    }
    
    /// Force a retry - call this after watch app is confirmed running
    func retrySyncIfNeeded() {
        guard let session = session else { return }
        Design.debugLog("WatchConnectivity: Manual retry - paired: \(session.isPaired), installed: \(session.isWatchAppInstalled), reachable: \(session.isReachable)")
        
        if let cards = pendingCards {
            pendingCards = nil
            syncCards(cards)
        }
    }
    
    private func createSyncableCard(from card: BusinessCard) -> SyncableCard {
        // Get first email, phone, website, location from contact fields
        let email = card.firstContactField(ofType: "email")?.value ?? ""
        let phone = card.firstContactField(ofType: "phone")?.value ?? ""
        let website = card.firstContactField(ofType: "website")?.value ?? ""
        let linkedIn = card.firstContactField(ofType: "linkedIn")?.value ?? ""
        let twitter = card.firstContactField(ofType: "twitter")?.value ?? ""
        let instagram = card.firstContactField(ofType: "instagram")?.value ?? ""
        
        // Format address for display (decode from stored JSON/legacy format)
        let addressValue = card.firstContactField(ofType: "address")?.value ?? ""
        let location = PostalAddress.decode(from: addressValue)?.singleLineString ?? addressValue
        
        // Build vCard payload for QR code generation (use vCardName for compatibility)
        let vCardPayload = buildVCardPayload(
            displayName: card.vCardName,
            company: card.company,
            role: card.role,
            phone: phone,
            email: email,
            website: website,
            location: location,
            bio: card.bio,
            linkedIn: linkedIn,
            twitter: twitter,
            instagram: instagram
        )
        
        // Generate QR code image data on iOS (CoreImage not available on watchOS)
        let qrImageData = generateQRCodePNGData(from: vCardPayload)
        
        // Use fullName - the single source of truth for display names
        let syncDisplayName = card.fullName
        Design.debugLog("WatchConnectivity: Syncing card '\(syncDisplayName)'")
        
        return SyncableCard(
            id: card.id,
            fullName: syncDisplayName,
            role: card.role,
            company: card.company,
            email: email,
            phone: phone,
            website: website,
            location: location,
            isDefault: card.isDefault,
            pronouns: card.pronouns,
            bio: card.bio,
            linkedIn: linkedIn,
            twitter: twitter,
            instagram: instagram,
            qrCodeImageData: qrImageData
        )
    }
    
    private func buildVCardPayload(
        displayName: String,
        company: String,
        role: String,
        phone: String,
        email: String,
        website: String,
        location: String,
        bio: String,
        linkedIn: String,
        twitter: String,
        instagram: String
    ) -> String {
        var lines = [
            "BEGIN:VCARD",
            "VERSION:3.0",
            "FN:\(displayName)",
            "ORG:\(company)",
            "TITLE:\(role)"
        ]
        
        if !phone.isEmpty {
            lines.append("TEL;TYPE=work:\(phone)")
        }
        if !email.isEmpty {
            lines.append("EMAIL;TYPE=work:\(email)")
        }
        if !website.isEmpty {
            lines.append("URL:\(website)")
        }
        if !location.isEmpty {
            lines.append("ADR;TYPE=work:;;\(location)")
        }
        if !bio.isEmpty {
            lines.append("NOTE:\(bio)")
        }
        if !linkedIn.isEmpty {
            lines.append("X-SOCIALPROFILE;TYPE=linkedin:\(linkedIn)")
        }
        if !twitter.isEmpty {
            lines.append("X-SOCIALPROFILE;TYPE=twitter:\(twitter)")
        }
        if !instagram.isEmpty {
            lines.append("X-SOCIALPROFILE;TYPE=instagram:\(instagram)")
        }
        
        lines.append("END:VCARD")
        return lines.joined(separator: "\n")
    }
    
    private func generateQRCodePNGData(from payload: String) -> Data? {
        let context = CIContext()
        let data = Data(payload.utf8)
        let filter = CIFilter.qrCodeGenerator()
        filter.setValue(data, forKey: "inputMessage")
        filter.correctionLevel = "M"
        
        guard let outputImage = filter.outputImage else { return nil }
        
        // Scale up for better quality on watch display
        let scaledImage = outputImage.transformed(by: CGAffineTransform(scaleX: 10, y: 10))
        
        guard let cgImage = context.createCGImage(scaledImage, from: scaledImage.extent) else { return nil }
        
        // Convert to PNG data for syncing
        let uiImage = UIImage(cgImage: cgImage)
        return uiImage.pngData()
    }
}

// MARK: - WCSessionDelegate

extension WatchConnectivityService: WCSessionDelegate {
    nonisolated func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        Task { @MainActor in
            if let error = error {
                Design.debugLog("WatchConnectivity: Activation failed: \(error)")
            } else {
                Design.debugLog("WatchConnectivity: Activated with state: \(activationState.rawValue)")
                WatchConnectivityService.shared.handleActivation()
            }
        }
    }
    
    nonisolated func sessionDidBecomeInactive(_ session: WCSession) {
        Task { @MainActor in
            Design.debugLog("WatchConnectivity: Session became inactive")
        }
    }
    
    nonisolated func sessionDidDeactivate(_ session: WCSession) {
        Task { @MainActor in
            Design.debugLog("WatchConnectivity: Session deactivated, reactivating...")
            WCSession.default.activate()
        }
    }
}

/// A simplified card structure that can be shared between iOS and watchOS
struct SyncableCard: Codable, Identifiable {
    let id: UUID
    var fullName: String
    var role: String
    var company: String
    var email: String
    var phone: String
    var website: String
    var location: String
    var isDefault: Bool
    var pronouns: String
    var bio: String
    var linkedIn: String
    var twitter: String
    var instagram: String
    /// Pre-generated QR code PNG data (CoreImage not available on watchOS)
    var qrCodeImageData: Data?
}
