//
//  SharedMoodIntent.swift
//  Reflect
//
//  Single VoteMoodIntent for all targets.
//  Main app uses ForegroundContinuableIntent to run widget intents in app process.
//
//  Add this file to ALL targets: Reflect (iOS), ReflectWidgetExtension, Reflect Watch App
//

import AppIntents
import SwiftUI
import SwiftData
import WidgetKit
import os.log

// MARK: - Vote Mood Intent

struct VoteMoodIntent: AppIntent {
    static var title: LocalizedStringResource = "Vote Mood"
    static var description = IntentDescription("Record your mood for today")

    static var openAppWhenRun: Bool = false

    @Parameter(title: "Mood")
    var moodValue: Int

    init() {
        self.moodValue = 2
    }

    init(mood: Mood) {
        self.moodValue = mood.rawValue
    }

    @MainActor
    func perform() async throws -> some IntentResult {
        let mood = Mood(rawValue: moodValue) ?? .average

        #if os(watchOS)
        // Watch: Send to iPhone via WatchConnectivity
        let date = Date()
        _ = WatchConnectivityManager.shared.sendMoodToPhone(mood: moodValue, date: date)
        WidgetCenter.shared.reloadAllTimelines()

        #elseif WIDGET_EXTENSION
        // Widget: Save to shared container, main app handles side effects
        let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: UserDefaultsStore.getOnboarding())
        WidgetMoodSaver.save(mood: mood, date: votingDate)
        WidgetCenter.shared.reloadAllTimelines()

        #else
        // Main app: Full logging with all side effects
        let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: UserDefaultsStore.getOnboarding())
        MoodLogger.shared.logMood(mood, for: votingDate, entryType: .widget)

        let dateString = ISO8601DateFormatter().string(from: Calendar.current.startOfDay(for: votingDate))
        GroupUserDefaults.groupDefaults.set(dateString, forKey: UserDefaultsStore.Keys.lastVotedDate.rawValue)
        #endif

        return .result()
    }
}

// MARK: - Main App: Run widget intents in app process

#if !WIDGET_EXTENSION && !os(watchOS)
extension VoteMoodIntent: ForegroundContinuableIntent {}
#endif

// MARK: - Widget: Save to shared container

#if WIDGET_EXTENSION
enum WidgetMoodSaver {
    private static let logger = Logger(subsystem: "com.88oakapps.reflect.widget", category: "WidgetMoodSaver")
    private static var cachedContainer: ModelContainer?

    @MainActor
    static func save(mood: Mood, date: Date) {
        do {
            let container = try getOrCreateContainer()
            try performSave(mood: mood, date: date, container: container)
        } catch {
            // Container may be stale or corrupted — discard cache and retry once
            logger.warning("First save attempt failed, retrying with fresh container: \(error.localizedDescription)")
            cachedContainer = nil
            do {
                let container = try getOrCreateContainer()
                try performSave(mood: mood, date: date, container: container)
            } catch {
                logger.error("Failed to save mood after retry: \(error.localizedDescription)")
            }
        }
    }

    private static func getOrCreateContainer() throws -> ModelContainer {
        if let existing = cachedContainer {
            return existing
        }

        let schema = Schema([MoodEntryModel.self])
        let appGroupID = Constants.currentGroupShareId

        guard let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupID) else {
            logger.error("App Group not available")
            throw WidgetMoodSaverError.appGroupUnavailable
        }

        #if DEBUG
        let storeURL = containerURL.appendingPathComponent("Reflect-Debug.store")
        #else
        let storeURL = containerURL.appendingPathComponent("Reflect.store")
        #endif

        let config = ModelConfiguration(schema: schema, url: storeURL, cloudKitDatabase: .none)
        let container = try ModelContainer(for: schema, configurations: [config])
        cachedContainer = container
        return container
    }

    @MainActor
    private static func performSave(mood: Mood, date: Date, container: ModelContainer) throws {
        let context = container.mainContext

        // Delete existing entry for this date
        let startDate = Calendar.current.startOfDay(for: date)
        let endDate = Calendar.current.date(byAdding: .day, value: 1, to: startDate)!

        let descriptor = FetchDescriptor<MoodEntryModel>(
            predicate: #Predicate { entry in
                entry.forDate >= startDate && entry.forDate < endDate
            }
        )

        let existing = try context.fetch(descriptor)
        if !existing.isEmpty {
            for entry in existing {
                context.delete(entry)
            }
            try context.save()
        }

        // Create new entry
        let entry = MoodEntryModel(forDate: date, mood: mood, entryType: .widget)
        context.insert(entry)
        try context.save()
        logger.info("Saved mood \(mood.rawValue) from widget")

        // Note: The widget cannot run full side effects (HealthKit, streaks, analytics, etc.)
        // because it runs in a separate extension process without access to MoodLogger.
        // When the main app returns to the foreground, it calls
        // MoodLogger.shared.processPendingSideEffects() to catch up on any side effects
        // that were missed from widget or watch entries.
    }

    enum WidgetMoodSaverError: LocalizedError {
        case appGroupUnavailable

        var errorDescription: String? {
            switch self {
            case .appGroupUnavailable:
                return "App Group container is not available"
            }
        }
    }
}
#endif
