import CryptoKit
import Foundation

enum HashService {
    private static let iso8601Formatter: ISO8601DateFormatter = {
        let f = ISO8601DateFormatter()
        f.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        return f
    }()

    // SHA256 of "typeIdentifier|totalCount|earliestDateISO|latestDateISO"
    // ⚠️ MVP limitation: hash covers only count + date range, not value distribution.
    // silentReplacement detection based on this hash is best-effort only —
    // it will miss replacements that preserve total count and date boundaries.
    static func typeHash(
        typeIdentifier: String,
        totalCount: Int,
        earliestDate: Date?,
        latestDate: Date?
    ) -> String {
        let earliest = earliestDate.map { iso8601Formatter.string(from: $0) } ?? ""
        let latest   = latestDate.map   { iso8601Formatter.string(from: $0) } ?? ""
        let input = "\(typeIdentifier)|\(totalCount)|\(earliest)|\(latest)"
        let digest = SHA256.hash(data: Data(input.utf8))
        return digest.map { String(format: "%02x", $0) }.joined()
    }

    // Per-snapshot: sort TypeCounts by typeIdentifier, SHA256 of concatenated type hashes.
    // Filter criterion: quality == .complete — do NOT use hash != "" as a proxy.
    // A TypeCount with quality = .failed but hash = "nonEmpty" (e.g. from a prior bug) must
    // be excluded. Filtering on hash != "" would include it, producing a non-deterministic checksum.
    static func snapshotChecksum(typeCounts: [TypeCount]) -> String {
        let completeHashes = typeCounts
            .filter { $0.quality == .complete }
            .sorted { $0.typeIdentifier < $1.typeIdentifier }
            .map { $0.hash }
            .joined()
        let digest = SHA256.hash(data: Data(completeHashes.utf8))
        return digest.map { String(format: "%02x", $0) }.joined()
    }

    // SHA256 of sorted active typeIdentifier strings.
    // ⚠️ Covers the FULL intended registry (selectedTypeIDs), including types that may have
    // failed, timed out, or been unauthorized — never filter down to only the successfully-
    // fetched subset. A query failure must not silently change the registry hash.
    static func typeSetHash(typeIDs: [String]) -> String {
        let sorted = typeIDs.sorted().joined(separator: "|")
        let digest = SHA256.hash(data: Data(sorted.utf8))
        return digest.map { String(format: "%02x", $0) }.joined()
    }
}
