import Foundation
import PostHog
import SwiftUI
import UIKit

@MainActor
final class AnalyticsManager {

    // MARK: - Singleton

    static let shared = AnalyticsManager()
    private init() {}

    // MARK: - Configuration

    #if DEBUG
    // FIXME: Replace with separate production API key to prevent debug events polluting production analytics
    private static let apiKey = "phc_DEVELOPMENT_KEY_REPLACE_ME"
    #else
    private static let apiKey = "phc_oeZddTz7Iw0NxDXFeCycS7TG9YRVtv7WP2DjOvFPUeQ"
    #endif

    private static let host = "https://analytics.88oakapps.com"

    private static let optOutKey = "analyticsOptedOut"
    private static let sessionReplayKey = "analytics_session_replay_enabled"

    private var isConfigured = false

    // MARK: - ISO8601 Formatter

    private static let iso8601Formatter: ISO8601DateFormatter = {
        let f = ISO8601DateFormatter()
        f.formatOptions = [.withInternetDateTime]
        return f
    }()

    // MARK: - Setup

    func configure() {
        guard !isConfigured else { return }

        let config = PostHogConfig(apiKey: Self.apiKey, host: Self.host)

        // Anonymous person profiles — no user identification, but PostHog can
        // count unique visitors and tie sessions to anonymous device IDs
        config.personProfiles = .always

        // Auto-capture
        config.captureElementInteractions = true
        config.captureApplicationLifecycleEvents = true
        config.captureScreenViews = true

        // Session replay
        config.sessionReplay = sessionReplayEnabled
        config.sessionReplayConfig.maskAllTextInputs = true
        config.sessionReplayConfig.maskAllImages = false
        config.sessionReplayConfig.captureNetworkTelemetry = true
        config.sessionReplayConfig.screenshotMode = true // Required for SwiftUI

        // Respect user opt-out preference
        if isOptedOut {
            config.optOut = true
        }

        #if DEBUG
        config.debug = false
        config.flushAt = 1
        #endif

        PostHogSDK.shared.setup(config)
        isConfigured = true

        updateSuperProperties()
    }

    // MARK: - Event Tracking

    func track(_ event: AnalyticsEvent) {
        guard isConfigured else { return }
        let (name, properties) = event.payload
        PostHogSDK.shared.capture(name, properties: properties)
    }

    // MARK: - Screen Tracking

    func trackScreen(_ screen: Screen, properties: [String: Any]? = nil) {
        guard isConfigured else { return }
        var props: [String: Any] = ["screen_name": screen.rawValue]
        if let properties { props.merge(properties) { _, new in new } }
        PostHogSDK.shared.capture("screen_viewed", properties: props)
    }

    // MARK: - Exception / Crash Capture

    /// Capture a Swift Error as a PostHog `$exception` event.
    func captureException(_ error: Error, properties: [String: Any]? = nil) {
        guard isConfigured else { return }
        var props: [String: Any] = [
            "$exception_type": String(describing: type(of: error)),
            "$exception_message": error.localizedDescription,
            "$exception_stack_trace_raw": Thread.callStackSymbols.joined(separator: "\n")
        ]
        if let properties { props.merge(properties) { _, new in new } }
        PostHogSDK.shared.capture("$exception", properties: props)
    }

    /// Capture an NSException as a PostHog `$exception` event.
    func captureNSException(_ exception: NSException, isFatal: Bool = false) {
        guard isConfigured else { return }
        PostHogSDK.shared.capture("$exception", properties: [
            "$exception_type": exception.name.rawValue,
            "$exception_message": exception.reason ?? "No reason",
            "$exception_stack_trace_raw": exception.callStackSymbols.joined(separator: "\n"),
            "$exception_is_fatal": isFatal
        ])
    }

    /// Install an uncaught NSException handler that captures crashes to PostHog
    /// before the app terminates. Call this once after configure().
    func setupExceptionHandler() {
        NSSetUncaughtExceptionHandler { exception in
            // Cannot use AnalyticsManager.shared here (may deadlock on @MainActor),
            // so call PostHogSDK directly.
            PostHogSDK.shared.capture("$exception", properties: [
                "$exception_type": exception.name.rawValue,
                "$exception_message": exception.reason ?? "No reason",
                "$exception_stack_trace_raw": exception.callStackSymbols.joined(separator: "\n"),
                "$exception_is_fatal": true
            ])
            PostHogSDK.shared.flush()
        }
    }

    // MARK: - Flush & Reset

    func flush() {
        guard isConfigured else { return }
        PostHogSDK.shared.flush()
    }

    func reset() {
        guard isConfigured else { return }
        PostHogSDK.shared.reset()
    }

    // MARK: - Super Properties

    func updateSuperProperties() {
        let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown"
        let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "unknown"
        let device = UIDevice.current.model
        let osVersion = UIDevice.current.systemVersion

        var props: [String: Any] = [
            "app_version": version,
            "build_number": build,
            "device_model": device,
            "os_version": osVersion,
            "is_pro": SubscriptionCacheWrapper.shared.currentTier == "pro",
            "animations_enabled": !UIAccessibility.isReduceMotionEnabled,
        ]

        PostHogSDK.shared.register(props)
    }

    // MARK: - Subscription Funnel

    func trackPaywallViewed(source: String) {
        guard isConfigured else { return }
        PostHogSDK.shared.capture("paywall_viewed", properties: ["source": source])
    }

    func trackPurchaseStarted(productId: String, source: String) {
        guard isConfigured else { return }
        PostHogSDK.shared.capture("purchase_started", properties: [
            "product_id": productId,
            "source": source,
        ])
    }

    func trackPurchaseCompleted(productId: String, source: String) {
        guard isConfigured else { return }
        PostHogSDK.shared.capture("purchase_completed", properties: [
            "product_id": productId,
            "source": source,
        ])
    }

    func trackPurchaseFailed(productId: String?, source: String, error: String) {
        guard isConfigured else { return }
        var props: [String: Any] = ["source": source, "error": error]
        if let productId { props["product_id"] = productId }
        PostHogSDK.shared.capture("purchase_failed", properties: props)
    }

    func trackPurchaseRestored(source: String) {
        guard isConfigured else { return }
        PostHogSDK.shared.capture("purchase_restored", properties: ["source": source])
    }

    // MARK: - Subscription Status (Person Properties)

    func trackSubscriptionStatusObserved(
        status: String,
        type: String,
        source: String,
        isSubscribed: Bool,
        hasFullAccess: Bool,
        productId: String?,
        willAutoRenew: Bool?,
        isInGracePeriod: Bool?,
        trialDaysRemaining: Int?,
        expirationDate: Date?
    ) {
        guard isConfigured else { return }

        var props: [String: Any] = [
            "status": status,
            "type": type,
            "source": source,
            "is_subscribed": isSubscribed,
            "has_full_access": hasFullAccess,
        ]

        if let productId { props["product_id"] = productId }
        if let willAutoRenew { props["will_auto_renew"] = willAutoRenew }
        if let isInGracePeriod { props["is_in_grace_period"] = isInGracePeriod }
        if let trialDaysRemaining { props["trial_days_remaining"] = trialDaysRemaining }
        if let expirationDate { props["expiration_date"] = Self.iso8601Formatter.string(from: expirationDate) }

        PostHogSDK.shared.capture("subscription_status_changed", properties: props)
        updateSubscriptionPersonProperties(status, type: type)
    }

    private func updateSubscriptionPersonProperties(_ status: String, type: String) {
        guard isConfigured else { return }
        PostHogSDK.shared.capture("$set", properties: [
            "$set": [
                "subscription_status": status,
                "subscription_type": type,
            ],
        ])
    }

    // MARK: - Opt-Out / Opt-In

    var isOptedOut: Bool {
        UserDefaults.standard.bool(forKey: Self.optOutKey)
    }

    func optIn() {
        UserDefaults.standard.set(false, forKey: Self.optOutKey)
        if isConfigured {
            PostHogSDK.shared.optIn()
            PostHogSDK.shared.capture("analytics_toggled", properties: ["enabled": true])
        }
    }

    func optOut() {
        if isConfigured {
            PostHogSDK.shared.capture("analytics_toggled", properties: ["enabled": false])
        }
        UserDefaults.standard.set(true, forKey: Self.optOutKey)
        if isConfigured {
            PostHogSDK.shared.optOut()
        }
    }

    // MARK: - Session Replay Control

    var sessionReplayEnabled: Bool {
        get {
            if UserDefaults.standard.object(forKey: Self.sessionReplayKey) == nil {
                return false
            }
            return UserDefaults.standard.bool(forKey: Self.sessionReplayKey)
        }
        set {
            UserDefaults.standard.set(newValue, forKey: Self.sessionReplayKey)
            if newValue {
                PostHogSDK.shared.startSessionRecording()
            } else {
                PostHogSDK.shared.stopSessionRecording()
            }
        }
    }
}

// MARK: - Screen Enum

extension AnalyticsManager {
    enum Screen: String {
        case registration = "registration"
        case residences = "residences"
        case newResidence = "new_residence"
        case tasks = "tasks"
        case newTask = "new_task"
        case contractors = "contractors"
        case newContractor = "new_contractor"
        case documents = "documents"
        case newDocument = "new_document"
        case settings = "settings"
        case notificationSettings = "notification_settings"
        case paywall = "paywall"
    }
}

// MARK: - SwiftUI Screen Tracking Modifier

struct ScreenTrackingModifier: ViewModifier {
    let screen: AnalyticsManager.Screen
    let properties: [String: Any]?

    func body(content: Content) -> some View {
        content.onAppear {
            AnalyticsManager.shared.trackScreen(screen, properties: properties)
        }
    }
}

extension View {
    func trackScreen(_ screen: AnalyticsManager.Screen, properties: [String: Any]? = nil) -> some View {
        modifier(ScreenTrackingModifier(screen: screen, properties: properties))
    }
}
