import Foundation
import WidgetKit

struct CompanionWidgetEntry: TimelineEntry {
    let date: Date
    let snapshot: CompanionWidgetSnapshot
}

struct CompanionWidgetProvider: TimelineProvider {
    func placeholder(in context: Context) -> CompanionWidgetEntry {
        CompanionWidgetEntry(date: .now, snapshot: .placeholder)
    }

    func getSnapshot(in context: Context, completion: @escaping (CompanionWidgetEntry) -> Void) {
        completion(
            CompanionWidgetEntry(
                date: .now,
                snapshot: CompanionWidgetSnapshotStore.load() ?? .placeholder
            )
        )
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<CompanionWidgetEntry>) -> Void) {
        let snapshot = CompanionWidgetSnapshotStore.load() ?? .placeholder
        let now = Date()

        // Generate entries at every upcoming event boundary so the widget
        // reflects live/past state accurately without waiting for the OS budget.
        let boundaries = snapshot.upcomingEvents
            .flatMap { [$0.startDate, $0.endDate] }
            .filter { $0 > now && $0 < now.addingTimeInterval(24 * 3_600) }
            .sorted()

        var dates = [now]
        dates.append(contentsOf: boundaries)

        let entries = dates.map { CompanionWidgetEntry(date: $0, snapshot: snapshot) }

        // Ask for fresh data at next event start (or 15 min), whichever is sooner.
        let nextRefresh = boundaries.first.map { min($0, now.addingTimeInterval(15 * 60)) }
            ?? now.addingTimeInterval(15 * 60)

        completion(Timeline(entries: entries, policy: .after(nextRefresh)))
    }
}

enum CompanionWidgetSnapshotStore {
    static func load() -> CompanionWidgetSnapshot? {
        guard let containerURL = FileManager.default.containerURL(
            forSecurityApplicationGroupIdentifier: CompanionWidgetSharedContainer.appGroupID
        ) else {
            return nil
        }

        let url = containerURL.appendingPathComponent(CompanionWidgetSharedContainer.widgetSnapshotFilename)
        guard let data = try? Data(contentsOf: url) else {
            return nil
        }

        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        return try? decoder.decode(CompanionWidgetSnapshot.self, from: data)
    }
}
