import AsyncAlgorithms
import Combine
import ComponentLibrary
import ComposableArchitecture
import Foundation
import SwiftUI

@DependencyClient
public struct ToastClient {
    // MARK: - API

    /// Shows a toast with the given parameters
    /// - Parameters:
    ///   - title: Optional title for the toast
    ///   - message: The message to display (either string or attributed string)
    ///   - style: The visual style of the toast (warning, success, etc.)
    ///   - position: Where to display the toast (top or bottom)
    ///   - trailingAccessory: Optional trailing accessory view for the toast
    public var show: (
        _ toast: ToastReducer.State.ToastType
    ) -> Void = { _ in }

    /// Dismisses the toast at the specified position
    public var dismiss: (_ position: Toast.Position) -> Void = { _ in }

    public var undo: () -> Void = {}

    public var tap: () -> Void = {}

    /// Stream of toast events that can be used to react to toast interactions
    public var stream: () -> AsyncStream<ToastEvent> = { .never }

    public enum ToastEvent: Equatable {
        case show(ToastReducer.State.ToastType)
        case dismiss(Toast.Position)
        case undo
        case tap
    }
}

extension ToastClient: DependencyKey {
    public static let liveValue: Self = {
        let subject = PassthroughSubject<ToastEvent, Never>()
        var activeToastId: UUID?

        return Self(
            show: { toast in
                activeToastId = toast.id
                subject.send(.show(toast))
            },
            dismiss: { position in
                activeToastId = nil
                subject.send(.dismiss(position))
            },
            undo: {
                guard activeToastId != nil else { return }
                subject.send(.undo)
            },
            tap: {
                guard activeToastId != nil else { return }
                subject.send(.tap)
            },
            stream: {
                UncheckedSendable(subject.values).eraseToStream()
            }
        )
    }()
}

extension ToastClient: TestDependencyKey {
    public static let previewValue = Self()
    public static let testValue = Self()
}

public extension DependencyValues {
    var toastClient: ToastClient {
        get { self[ToastClient.self] }
        set { self[ToastClient.self] = newValue }
    }
}
