import Foundation
import SwiftData

/// The user's active vocab-flashcard study set, persisted and CloudKit-synced
/// so the same group of verbs follows them across launches and across devices.
/// A new group is created when the previous one is fully learned.
///
/// CloudKit-synced; uniqueness on `id` is enforced in code (CloudKit forbids
/// `@Attribute(.unique)`). There is one active standard group at a time.
@Model
final class VocabStudyGroup {
    var id: String = ""
    /// JSON-encoded `[StoredVocabEntry]` — the in-session queue (un-graduated
    /// verbs only) in order, each with its learning-step state.
    var entriesJSON: Data = Data()
    var learnedCount: Int = 0
    var createdAt: Date = Date()

    init(entriesJSON: Data, learnedCount: Int) {
        self.id = Self.activeID
        self.entriesJSON = entriesJSON
        self.learnedCount = learnedCount
        self.createdAt = Date()
    }

    /// Single active standard-session group.
    static let activeID = "active-standard"

    var entries: [StoredVocabEntry] {
        (try? JSONDecoder().decode([StoredVocabEntry].self, from: entriesJSON)) ?? []
    }
}

/// One verb's persisted spot in the study group.
struct StoredVocabEntry: Codable {
    var verbId: Int
    /// Raw value of `VocabSessionQueue.CardState`.
    var state: String
}

/// Fetch / persist / clear the active study group. Operates on the cloud
/// context so the group syncs across devices.
struct VocabStudyGroupStore {
    let context: ModelContext

    /// The current active group, or nil. If duplicate records exist (two
    /// devices both created one before sync settled), the newest wins.
    func activeGroup() -> VocabStudyGroup? {
        let id = VocabStudyGroup.activeID
        let descriptor = FetchDescriptor<VocabStudyGroup>(
            predicate: #Predicate<VocabStudyGroup> { $0.id == id },
            sortBy: [SortDescriptor(\VocabStudyGroup.createdAt, order: .reverse)]
        )
        return (try? context.fetch(descriptor))?.first
    }

    /// Write the in-progress group, creating it if needed. If duplicate records
    /// exist (two devices created a group before sync settled), the newest is
    /// updated and the rest deleted so a single record survives.
    func persist(entries: [StoredVocabEntry], learnedCount: Int) {
        let data = (try? JSONEncoder().encode(entries)) ?? Data()
        let id = VocabStudyGroup.activeID
        let descriptor = FetchDescriptor<VocabStudyGroup>(
            predicate: #Predicate<VocabStudyGroup> { $0.id == id },
            sortBy: [SortDescriptor(\VocabStudyGroup.createdAt, order: .reverse)]
        )
        let existing = (try? context.fetch(descriptor)) ?? []
        if let newest = existing.first {
            newest.entriesJSON = data
            newest.learnedCount = learnedCount
            for duplicate in existing.dropFirst() { context.delete(duplicate) }
        } else {
            context.insert(VocabStudyGroup(entriesJSON: data, learnedCount: learnedCount))
        }
        try? context.save()
    }

    /// Remove the active group (and any duplicates) — the set is finished.
    func clear() {
        let id = VocabStudyGroup.activeID
        let descriptor = FetchDescriptor<VocabStudyGroup>(
            predicate: #Predicate<VocabStudyGroup> { $0.id == id }
        )
        for group in (try? context.fetch(descriptor)) ?? [] {
            context.delete(group)
        }
        try? context.save()
    }
}
