import Accessibility
import Foundation
import Observation

/// The observable model that owns the lifecycle of the transient in-app notifications.
///
/// Posting a notification appends it to ``notifications``, announces its message to assistive technologies — since the visual
/// banners are transient — and schedules its automatic dismissal a few seconds later, which is the only way a notification is
/// dismissed.
@MainActor
@Observable
public final class Notifier {

    // MARK: Properties

    /// The notifications currently presented, in post order.
    public private(set) var notifications: [AppNotification] = []

    /// The time a posted notification stays visible before its automatic dismissal.
    @ObservationIgnored
    private let delayDismissal: Duration

    // MARK: Initializers

    /// Creates a notifier.
    ///
    /// - Parameter delayDismissal: The time a posted notification stays visible before its automatic dismissal.
    /// Defaults to four seconds.
    public init(
        delayDismissal: Duration = .seconds(4)
    ) {
        self.delayDismissal = delayDismissal
    }

    // MARK: Methods

    /// Posts a notification, announcing its message to assistive technologies and scheduling its automatic dismissal.
    ///
    /// - Parameters:
    ///   - kind: The kind of the notification.
    ///   - message: The localized message of the notification.
    ///   - symbol: The system symbol of the notification's icon.
    public func post(
        _ kind: AppNotification.Kind,
        message: String,
        symbol: String
    ) {
        let notification = AppNotification(
            kind: kind,
            message: message,
            symbol: symbol
        )

        notifications.append(notification)

        AccessibilityNotification.Announcement(message).post()

        Task {
            try? await Task.sleep(for: delayDismissal)

            notifications.removeAll { $0.id == notification.id }
        }
    }

}
