import Foundation
import SwiftData

struct HealthRecordValue: Codable, Hashable, Identifiable, Sendable {
    var id: String { recordFingerprint }
    let typeIdentifier: String
    let sampleUUIDHash: String
    let recordFingerprint: String
    let startDate: Date
    let endDate: Date
    let displayValue: String?
}

enum HealthRecordArchive {
    private static let compactMagic = Data([0x48, 0x50, 0x52, 0x41, 0x32]) // HPRA2

    static func encode(_ values: [HealthRecordValue]) -> Data? {
        guard let typeIdentifier = values.first?.typeIdentifier else {
            return encodeCompact(typeIdentifier: "", values: [])
        }
        return encodeCompact(typeIdentifier: typeIdentifier, values: values)
    }

    static func decode(_ data: Data) -> [HealthRecordValue]? {
        if let decoded = decodeCompact(data) {
            return decoded
        }
        return try? PropertyListDecoder().decode([HealthRecordValue].self, from: data)
    }

    static func makeCompactWriter(typeIdentifier: String, estimatedRecordCount: Int = 0) -> CompactWriter {
        CompactWriter(typeIdentifier: typeIdentifier, estimatedRecordCount: estimatedRecordCount)
    }

    private static func encodeCompact(typeIdentifier: String, values: [HealthRecordValue]) -> Data? {
        var writer = makeCompactWriter(typeIdentifier: typeIdentifier, estimatedRecordCount: values.count)
        for value in values {
            writer.append(value)
        }
        return writer.finalize()
    }

    struct CompactWriter {
        private var data = Data()
        private var countOffset = 0
        private var count: UInt64 = 0

        init(typeIdentifier: String, estimatedRecordCount: Int = 0) {
            data.reserveCapacity(max(256, estimatedRecordCount * 160))
            data.append(compactMagic)
            appendString(typeIdentifier)
            countOffset = data.count
            appendUInt64(0)
        }

        mutating func append(_ value: HealthRecordValue) {
            appendString(value.sampleUUIDHash)
            appendString(value.recordFingerprint)
            appendDouble(value.startDate.timeIntervalSinceReferenceDate)
            appendDouble(value.endDate.timeIntervalSinceReferenceDate)
            appendOptionalString(value.displayValue)
            count += 1
        }

        mutating func finalize() -> Data {
            var littleEndianCount = count.littleEndian
            data.replaceSubrange(
                countOffset..<countOffset + MemoryLayout<UInt64>.size,
                with: withUnsafeBytes(of: &littleEndianCount) { Array($0) }
            )
            return data
        }

        private mutating func appendString(_ value: String) {
            let bytes = Array(value.utf8)
            appendUInt32(UInt32(bytes.count))
            data.append(contentsOf: bytes)
        }

        private mutating func appendOptionalString(_ value: String?) {
            guard let value else {
                appendInt32(-1)
                return
            }
            let bytes = Array(value.utf8)
            appendInt32(Int32(bytes.count))
            data.append(contentsOf: bytes)
        }

        private mutating func appendUInt32(_ value: UInt32) {
            var littleEndian = value.littleEndian
            data.append(contentsOf: withUnsafeBytes(of: &littleEndian) { Array($0) })
        }

        private mutating func appendInt32(_ value: Int32) {
            var littleEndian = value.littleEndian
            data.append(contentsOf: withUnsafeBytes(of: &littleEndian) { Array($0) })
        }

        private mutating func appendUInt64(_ value: UInt64) {
            var littleEndian = value.littleEndian
            data.append(contentsOf: withUnsafeBytes(of: &littleEndian) { Array($0) })
        }

        private mutating func appendDouble(_ value: Double) {
            appendUInt64(value.bitPattern)
        }
    }

    private static func decodeCompact(_ data: Data) -> [HealthRecordValue]? {
        guard data.starts(with: compactMagic) else { return nil }
        var reader = CompactReader(data: data, offset: compactMagic.count)
        guard let typeIdentifier = reader.readString(),
              let count = reader.readUInt64() else {
            return nil
        }

        var values: [HealthRecordValue] = []
        values.reserveCapacity(Int(min(count, UInt64(Int.max))))
        for _ in 0..<count {
            guard let sampleUUIDHash = reader.readString(),
                  let recordFingerprint = reader.readString(),
                  let startInterval = reader.readDouble(),
                  let endInterval = reader.readDouble(),
                  let displayValue = reader.readOptionalString() else {
                return nil
            }
            values.append(
                HealthRecordValue(
                    typeIdentifier: typeIdentifier,
                    sampleUUIDHash: sampleUUIDHash,
                    recordFingerprint: recordFingerprint,
                    startDate: Date(timeIntervalSinceReferenceDate: startInterval),
                    endDate: Date(timeIntervalSinceReferenceDate: endInterval),
                    displayValue: displayValue
                )
            )
        }
        return values
    }

    private struct CompactReader {
        let data: Data
        var offset: Int

        mutating func readString() -> String? {
            guard let length = readUInt32(),
                  let bytes = readBytes(count: Int(length)) else {
                return nil
            }
            return String(data: Data(bytes), encoding: .utf8)
        }

        mutating func readOptionalString() -> String?? {
            guard let length = readInt32() else { return nil }
            if length < 0 {
                return .some(nil)
            }
            guard let bytes = readBytes(count: Int(length)) else { return nil }
            return .some(String(data: Data(bytes), encoding: .utf8))
        }

        mutating func readUInt32() -> UInt32? {
            readFixedWidthInteger()
        }

        mutating func readInt32() -> Int32? {
            readFixedWidthInteger()
        }

        mutating func readUInt64() -> UInt64? {
            readFixedWidthInteger()
        }

        mutating func readDouble() -> Double? {
            guard let bitPattern: UInt64 = readFixedWidthInteger() else { return nil }
            return Double(bitPattern: bitPattern)
        }

        private mutating func readBytes(count: Int) -> [UInt8]? {
            guard count >= 0, offset + count <= data.count else { return nil }
            let bytes = Array(data[offset..<offset + count])
            offset += count
            return bytes
        }

        private mutating func readFixedWidthInteger<T: FixedWidthInteger>() -> T? {
            let size = MemoryLayout<T>.size
            guard let bytes = readBytes(count: size) else { return nil }
            return bytes.enumerated().reduce(T.zero) { result, item in
                result | (T(item.element) << T(item.offset * 8))
            }
        }
    }
}
// Interface updated 2026-05-12 — see AGENTS.md
@Model final class HealthRecord {
    var id: UUID = UUID()
    var typeIdentifier: String = ""
    var sampleUUIDHash: String = ""
    var recordFingerprint: String = ""
    var startDate: Date = Date.distantPast
    var endDate: Date = Date.distantPast
    var displayValue: String?
    var typeCount: TypeCount?

    init(
        typeIdentifier: String,
        sampleUUIDHash: String,
        recordFingerprint: String,
        startDate: Date,
        endDate: Date,
        displayValue: String? = nil
    ) {
        self.id = UUID()
        self.typeIdentifier = typeIdentifier
        self.sampleUUIDHash = sampleUUIDHash
        self.recordFingerprint = recordFingerprint
        self.startDate = startDate
        self.endDate = endDate
        self.displayValue = displayValue
    }
}
