//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
import SignalCoreKit
import SignalServiceKit
import SignalUI

class CommonCallState {
    let audioActivity: AudioActivity

    init(audioActivity: AudioActivity) {
        self.audioActivity = audioActivity
    }

    deinit {
        owsAssertDebug(systemState != .reported, "call \(localId) was reported to system but never removed")
    }

    // MARK: - Properties

    // Distinguishes between calls locally, e.g. in CallKit
    let localId: UUID = UUID()

    // MARK: - Connected Date

    // Should be used only on the main thread
    private(set) var connectedDate: MonotonicDate? {
        didSet { AssertIsOnMainThread() }
    }

    @discardableResult
    func setConnectedDateIfNeeded() -> Bool {
        guard self.connectedDate == nil else {
            return false
        }
        self.connectedDate = MonotonicDate()
        return true
    }

    // This method should only be called when the call state is "connected".
    func connectionDuration() -> TimeInterval {
        guard let connectedDate else {
            owsFailDebug("Called connectionDuration before connected.")
            return 0
        }
        return TimeInterval(MonotonicDate() - connectedDate) / TimeInterval(NSEC_PER_SEC)
    }

    // MARK: - System OS Interop

    private(set) var systemState: SystemState = .notReported
    enum SystemState {
        case notReported
        case pending
        case reported
        case removed
    }

    func markPendingReportToSystem() {
        owsAssertDebug(systemState == .notReported, "call \(localId) had unexpected system state: \(systemState)")
        systemState = .pending
    }

    func markReportedToSystem() {
        owsAssertDebug(systemState == .notReported || systemState == .pending,
                       "call \(localId) had unexpected system state: \(systemState)")
        systemState = .reported
    }

    func markRemovedFromSystem() {
        // This was an assert that was firing when coming back online after missing
        // a call while offline. See IOS-3416
        if systemState != .reported {
            Logger.warn("call \(localId) had unexpected system state: \(systemState)")
        }
        systemState = .removed
    }
}
