//
//  ReflectTips.swift
//  Reflect
//
//  Custom tips system for feature discovery and onboarding
//

import SwiftUI

// MARK: - ReflectTip Protocol

@MainActor
protocol ReflectTip: Identifiable {
    var id: String { get }
    var title: String { get }
    var message: String { get }
    var icon: String { get }
    var isEligible: Bool { get }
}

// MARK: - Tip Definitions

@MainActor
struct CustomizeLayoutTip: ReflectTip {
    let id = "customizeLayout"
    let title = "Personalize Your Experience"
    let message = "Customize mood icons, colors, and layouts to make the app truly yours."
    let icon = "paintbrush.fill"
    var isEligible: Bool { true }
}

@MainActor
struct AIInsightsTip: ReflectTip {
    let id = "aiInsights"
    let title = "Discover AI Insights"
    let message = "Get personalized insights about your mood patterns powered by Apple Intelligence."
    let icon = "brain.head.profile"
    var isEligible: Bool {
        ReflectTipsManager.shared.moodLogCount >= 7
    }
}

@MainActor
struct SiriShortcutTip: ReflectTip {
    let id = "siriShortcut"
    let title = "Use Siri to Log Moods"
    let message = "Say \"Hey Siri, log my mood as great in Reflect\" for hands-free logging."
    let icon = "mic.fill"
    var isEligible: Bool {
        ReflectTipsManager.shared.moodLogCount >= 3
    }
}

@MainActor
struct HealthKitSyncTip: ReflectTip {
    let id = "healthKitSync"
    let title = "Sync with Apple Health"
    let message = "Connect to Apple Health to see your mood data alongside sleep, exercise, and more."
    let icon = "heart.fill"
    var isEligible: Bool {
        ReflectTipsManager.shared.hasSeenSettings
    }
}

@MainActor
struct WidgetVotingTip: ReflectTip {
    let id = "widgetVoting"
    let title = "Vote from Your Home Screen"
    let message = "Add the Mood Vote widget to quickly log your mood without opening the app."
    let icon = "square.grid.2x2.fill"
    var isEligible: Bool {
        ReflectTipsManager.shared.daysUsingApp >= 2
    }
}

@MainActor
struct TimeViewTip: ReflectTip {
    let id = "timeView"
    let title = "View Your History"
    let message = "Switch between Day, Month, and Year views to see your mood patterns over time."
    let icon = "calendar"
    var isEligible: Bool { true }
}

@MainActor
struct MoodStreakTip: ReflectTip {
    let id = "moodStreak"
    let title = "Build Your Streak!"
    let message = "Log your mood daily to build a streak. Consistency helps you understand your patterns."
    let icon = "flame.fill"
    var isEligible: Bool {
        ReflectTipsManager.shared.currentStreak >= 3
    }
}

// MARK: - All Tips

@MainActor
enum ReflectTips {
    static let customizeLayout = CustomizeLayoutTip()
    static let aiInsights = AIInsightsTip()
    static let siriShortcut = SiriShortcutTip()
    static let healthKitSync = HealthKitSyncTip()
    static let widgetVoting = WidgetVotingTip()
    static let timeView = TimeViewTip()
    static let moodStreak = MoodStreakTip()
}

// MARK: - Tips Manager

@MainActor
class ReflectTipsManager: ObservableObject {
    static let shared = ReflectTipsManager()

    // MARK: - Keys
    private enum Keys {
        static let tipsEnabled = "reflect.tips.enabled"
        static let shownTipIDs = "reflect.tips.shownIDs"
        static let moodLogCount = "reflect.tips.moodLogCount"
        static let hasSeenSettings = "reflect.tips.hasSeenSettings"
        static let daysUsingApp = "reflect.tips.daysUsingApp"
        static let currentStreak = "reflect.tips.currentStreak"
    }

    // MARK: - Published State
    @Published var currentTip: (any ReflectTip)?
    @Published var showTipModal = false

    // MARK: - Global Toggle (configurable)
    var tipsEnabled: Bool {
        get { UserDefaults.standard.bool(forKey: Keys.tipsEnabled) }
        set { UserDefaults.standard.set(newValue, forKey: Keys.tipsEnabled) }
    }

    // MARK: - Session Tracking
    private(set) var hasShownTipThisSession = false

    // MARK: - Shown Tips (persisted)
    private var shownTipIDs: Set<String> {
        get {
            let array = UserDefaults.standard.stringArray(forKey: Keys.shownTipIDs) ?? []
            return Set(array)
        }
        set {
            UserDefaults.standard.set(Array(newValue), forKey: Keys.shownTipIDs)
        }
    }

    // MARK: - Tip Parameters (persisted)
    var moodLogCount: Int {
        get { UserDefaults.standard.integer(forKey: Keys.moodLogCount) }
        set { UserDefaults.standard.set(newValue, forKey: Keys.moodLogCount) }
    }

    var hasSeenSettings: Bool {
        get { UserDefaults.standard.bool(forKey: Keys.hasSeenSettings) }
        set { UserDefaults.standard.set(newValue, forKey: Keys.hasSeenSettings) }
    }

    var daysUsingApp: Int {
        get { UserDefaults.standard.integer(forKey: Keys.daysUsingApp) }
        set { UserDefaults.standard.set(newValue, forKey: Keys.daysUsingApp) }
    }

    var currentStreak: Int {
        get { UserDefaults.standard.integer(forKey: Keys.currentStreak) }
        set { UserDefaults.standard.set(newValue, forKey: Keys.currentStreak) }
    }

    // MARK: - Initialization
    private init() {
        // Set default value for tipsEnabled if not set
        if UserDefaults.standard.object(forKey: Keys.tipsEnabled) == nil {
            tipsEnabled = true
        }
    }

    // MARK: - Public API

    /// Check if a tip should be shown
    func shouldShowTip(_ tip: any ReflectTip) -> Bool {
        guard tipsEnabled else { return false }
        guard !hasShownTipThisSession else { return false }
        guard !shownTipIDs.contains(tip.id) else { return false }
        guard tip.isEligible else { return false }
        return true
    }

    /// Show a tip if eligible
    func showTipIfEligible(_ tip: any ReflectTip) {
        guard shouldShowTip(tip) else { return }
        currentTip = tip
        showTipModal = true
    }

    /// Mark a tip as shown (called when dismissed)
    func markTipAsShown(_ tip: any ReflectTip) {
        shownTipIDs.insert(tip.id)
        hasShownTipThisSession = true
        currentTip = nil
        showTipModal = false
    }

    /// Reset session flag (call on app launch)
    func resetSession() {
        hasShownTipThisSession = false
    }

    /// Reset all tips (for testing)
    func resetAllTips() {
        shownTipIDs = []
        hasShownTipThisSession = false
        moodLogCount = 0
        hasSeenSettings = false
        daysUsingApp = 0
        currentStreak = 0
    }

    // MARK: - Event Handlers

    func onMoodLogged() {
        moodLogCount += 1
    }

    func onSettingsViewed() {
        hasSeenSettings = true
    }

    func updateDaysUsingApp(_ days: Int) {
        daysUsingApp = days
    }

    func updateStreak(_ streak: Int) {
        currentStreak = streak
    }
}

// MARK: - View Modifier for Easy Integration

struct ReflectTipModifier: ViewModifier {
    let tip: any ReflectTip
    let gradientColors: [Color]

    // Use local state for sheet to avoid interference from other manager state changes
    @State private var showSheet = false
    @State private var hasCheckedEligibility = false

    func body(content: Content) -> some View {
        content
            .onAppear {
                // Only check eligibility once per view lifetime
                guard !hasCheckedEligibility else { return }
                hasCheckedEligibility = true

                // Delay tip presentation to ensure view hierarchy is fully established
                // This prevents "presenting from detached view controller" errors
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    if ReflectTipsManager.shared.shouldShowTip(tip) {
                        showSheet = true
                    }
                }
            }
            .sheet(isPresented: $showSheet) {
                TipModalView(
                    icon: tip.icon,
                    title: tip.title,
                    message: tip.message,
                    gradientColors: gradientColors,
                    onDismiss: {
                        showSheet = false
                        ReflectTipsManager.shared.markTipAsShown(tip)
                    }
                )
                .presentationDetents([.height(340)])
                .presentationDragIndicator(.visible)
                .presentationCornerRadius(28)
            }
    }
}

extension View {
    /// Attach a tip that shows as a themed modal when eligible
    func reflectTip(_ tip: any ReflectTip, gradientColors: [Color]) -> some View {
        modifier(ReflectTipModifier(tip: tip, gradientColors: gradientColors))
    }

    // MARK: - Convenience Modifiers

    /// Default gradient for tips
    private var defaultTipGradient: [Color] {
        [Color(hex: "667eea"), Color(hex: "764ba2")]
    }

    func customizeLayoutTip() -> some View {
        reflectTip(ReflectTips.customizeLayout, gradientColors: [Color(hex: "667eea"), Color(hex: "764ba2")])
    }

    func aiInsightsTip() -> some View {
        reflectTip(ReflectTips.aiInsights, gradientColors: [.purple, .blue])
    }

    func siriShortcutTip() -> some View {
        reflectTip(ReflectTips.siriShortcut, gradientColors: [Color(hex: "f093fb"), Color(hex: "f5576c")])
    }

    func healthKitSyncTip() -> some View {
        reflectTip(ReflectTips.healthKitSync, gradientColors: [.red, .pink])
    }

    func widgetVotingTip() -> some View {
        reflectTip(ReflectTips.widgetVoting, gradientColors: [Color(hex: "11998e"), Color(hex: "38ef7d")])
    }

    func timeViewTip() -> some View {
        reflectTip(ReflectTips.timeView, gradientColors: [.blue, .cyan])
    }

    func moodStreakTip() -> some View {
        reflectTip(ReflectTips.moodStreak, gradientColors: [.orange, .red])
    }
}
