import AdSupport
import APIClient
import AppTrackingTransparency
import ComposableArchitecture

@DependencyClient
public struct ATTClient {
    public var requestTrackingAuthorization: @Sendable () async -> ATTrackingManager.AuthorizationStatus = { .notDetermined }
    /// Returns `nil` if tracking is not authorized.
    /// It's better to expose this directly than to build an abstraction around `.authorized` and pass it along there because the `idfa` can change at any time.
    public var idfa: @Sendable () -> UUID? = { nil }

    public var uploadIdfaIfAppropriate: @Sendable (UUID) async throws -> Void = { _ in }
}

extension ATTClient: DependencyKey {
    public static let liveValue = Self(
        requestTrackingAuthorization: {
            await ATTrackingManager.requestTrackingAuthorization()
        },
        idfa: {
            guard ATTrackingManager.trackingAuthorizationStatus == .authorized else { return nil }
            return ASIdentifierManager.shared().advertisingIdentifier
        },
        uploadIdfaIfAppropriate: { idfa in
            try await APIClientV2.underlying.send(Paths.ads.user.post(AdsUserRequest(idfa: idfa.uuidString)))
        }
    )
}

extension ATTClient: TestDependencyKey {
    public static let previewValue = Self.noop
    public static let testValue: ATTClient = Self.noop
}

public extension ATTClient {
    static let noop = Self(
        requestTrackingAuthorization: { .notDetermined },
        idfa: { nil },
        uploadIdfaIfAppropriate: { _ in }
    )
}

public extension DependencyValues {
    var attClient: ATTClient {
        get { self[ATTClient.self] }
        set { self[ATTClient.self] = newValue }
    }
}
