import CryptoKit
import Foundation
import SwiftData

public enum CourseCardStore {
    private static var sortDescriptors: [SortDescriptor<VocabCard>] {
        [
            SortDescriptor(\VocabCard.deckId),
            SortDescriptor(\VocabCard.front),
            SortDescriptor(\VocabCard.back),
        ]
    }

    public static func reviewKey(for card: VocabCard) -> String {
        reviewKey(
            deckId: card.deckId,
            front: card.front,
            back: card.back,
            examplesES: card.examplesES,
            examplesEN: card.examplesEN
        )
    }

    public static func reviewKey(
        deckId: String,
        front: String,
        back: String,
        examplesES: [String],
        examplesEN: [String]
    ) -> String {
        let source = [
            deckId,
            front,
            back,
            examplesES.joined(separator: "\u{1F}"),
            examplesEN.joined(separator: "\u{1F}"),
        ].joined(separator: "\u{1E}")

        let digest = SHA256.hash(data: Data(source.utf8))
        return digest.map { String(format: "%02x", $0) }.joined()
    }

    public static func fetchCardCount(context: ModelContext) -> Int {
        (try? context.fetchCount(FetchDescriptor<VocabCard>())) ?? 0
    }

    public static func fetchCard(at index: Int, context: ModelContext) -> VocabCard? {
        guard index >= 0 else { return nil }
        var descriptor = FetchDescriptor<VocabCard>(sortBy: sortDescriptors)
        descriptor.fetchOffset = index
        descriptor.fetchLimit = 1
        return (try? context.fetch(descriptor))?.first
    }

    public static func fetchCards(offset: Int, limit: Int, context: ModelContext) -> [VocabCard] {
        guard limit > 0 else { return [] }
        var descriptor = FetchDescriptor<VocabCard>(sortBy: sortDescriptors)
        descriptor.fetchOffset = max(offset, 0)
        descriptor.fetchLimit = limit
        return (try? context.fetch(descriptor)) ?? []
    }

    public static func fetchWordOfDayCard(
        for date: Date,
        wordOffset: Int,
        context: ModelContext
    ) -> VocabCard? {
        let count = fetchCardCount(context: context)
        guard count > 0 else { return nil }

        let dayOfYear = Calendar.current.ordinality(of: .day, in: .year, for: date) ?? 1
        let index = (dayOfYear + wordOffset) % count
        return fetchCard(at: index, context: context)
    }
}
