//
//  DataController.swift
//  Reflect
//
//  SwiftData controller replacing Core Data PersistenceController.
//

import SwiftData
import SwiftUI
import os.log

@MainActor
final class DataController: ObservableObject {
    private static let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "com.88oakapps.reflect", category: "DataController")
    static let shared = DataController()

    private(set) var container: ModelContainer

    var modelContext: ModelContext {
        container.mainContext
    }


    // Listeners for data changes (keeping existing pattern)
    typealias DataListenerToken = UUID
    private var dataListeners: [DataListenerToken: () -> Void] = [:]

    // Computed properties for earliest/latest entries
    var earliestEntry: MoodEntryModel? {
        var descriptor = FetchDescriptor<MoodEntryModel>(
            sortBy: [SortDescriptor(\.forDate, order: .forward)]
        )
        descriptor.fetchLimit = 1
        return try? modelContext.fetch(descriptor).first
    }

    var latestEntry: MoodEntryModel? {
        var descriptor = FetchDescriptor<MoodEntryModel>(
            sortBy: [SortDescriptor(\.forDate, order: .reverse)]
        )
        descriptor.fetchLimit = 1
        return try? modelContext.fetch(descriptor).first
    }

    init(container: ModelContainer? = nil) {
        self.container = container ?? SharedModelContainer.createWithFallback(useCloudKit: true)
    }


    // MARK: - Listener Management

    @discardableResult
    func addNewDataListener(closure: @escaping (() -> Void)) -> DataListenerToken {
        let token = DataListenerToken()
        dataListeners[token] = closure
        return token
    }

    func removeDataListener(token: DataListenerToken) {
        dataListeners.removeValue(forKey: token)
    }

    @discardableResult
    func saveAndRunDataListeners() -> Bool {
        let success = save()
        if success {
            for closure in dataListeners.values {
                closure()
            }
        }
        return success
    }

    @discardableResult
    func save() -> Bool {
        guard modelContext.hasChanges else { return true }
        do {
            try modelContext.save()
            return true
        } catch {
            Self.logger.error("Failed to save context, retrying: \(error.localizedDescription)")
            do {
                try modelContext.save()
                return true
            } catch {
                Self.logger.critical("Failed to save context after retry: \(error.localizedDescription)")
                return false
            }
        }
    }

    /// Refresh data from disk to pick up changes made by extensions (widget/watch).
    /// Call this when app becomes active.
    func refreshFromDisk() {
        // SwiftData doesn't have a direct "refresh from disk" API.
        // We achieve this by:
        // 1. Rolling back any unsaved changes (ensures clean state)
        // 2. Triggering listeners to re-fetch data (which will read from disk)
        modelContext.rollback()

        // Notify listeners to re-fetch their data
        for closure in dataListeners.values {
            closure()
        }

        Self.logger.debug("Refreshed data from disk")
    }
}
