import Foundation

struct DeviceTime {

    let date: Date

    let secondsSincePowerOn: Int

    let totalNumberOfMeasurements: Int

    let secondsUntilNextMeasurement: Int

    let secondsOfFirstMeasurement: Int

    var nextMeasurement: Date {
        date.adding(seconds: secondsUntilNextMeasurement)
    }

    var deviceStartTime: Date {
        date.adding(seconds: -secondsSincePowerOn)
    }

    var estimatedMeasurementInterval: TimeInterval {
        guard totalNumberOfMeasurements > 0 else {
            return 60
        }
        return Double(secondsSincePowerOn + secondsUntilNextMeasurement) / Double(totalNumberOfMeasurements)
    }

    func measurementStartTime(measurementInterval interval: TimeInterval) -> Date {
        nextMeasurement.addingTimeInterval(-Double(totalNumberOfMeasurements) * interval)
    }

    func measurementOffset(measurementInterval interval: TimeInterval) -> TimeInterval {
        measurementStartTime(measurementInterval: interval).timeIntervalSince(deviceStartTime)
    }
}

extension DeviceTime: Equatable {
    
}

extension DeviceTime: Codable {

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        let time = try container.decode(Double.self)
        self.date = .init(timeIntervalSince1970: time)
        self.secondsSincePowerOn = try container.decode(Int.self)
        self.totalNumberOfMeasurements = try container.decode(Int.self)
        self.secondsUntilNextMeasurement = try container.decode(Int.self)
        self.secondsOfFirstMeasurement = try container.decode(Int.self)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        try container.encode(date.timeIntervalSince1970)
        try container.encode(secondsSincePowerOn)
        try container.encode(totalNumberOfMeasurements)
        try container.encode(secondsUntilNextMeasurement)
        try container.encode(secondsOfFirstMeasurement)
    }
}

extension DeviceTime {

    static var mock: DeviceTime {
        .init(
            date: .now,
            secondsSincePowerOn: 125,
            totalNumberOfMeasurements: 3,
            secondsUntilNextMeasurement: 55,
            secondsOfFirstMeasurement: 1)
    }
}
