import Foundation
import os

/// Client configuration
public struct DiagnosticsConfiguration: Sendable {
    public let productId: String
    public let userId: String?
    public let anonymousInstallId: String
    public let platform: String
    public let channel: String
    public let osFamily: String
    public let appVersion: String
    public let buildNumber: String
    public let releaseChannel: String
    public let serverUrl: String
    public let pollIntervalMs: Int
    public let maxBreadcrumbs: Int
    public let captureConsole: Bool
    public let captureErrors: Bool
    public let captureNetwork: Bool
    public let getAuthToken: (@Sendable () async throws -> String)?
    
    public init(
        productId: String,
        userId: String? = nil,
        anonymousInstallId: String,
        platform: String,
        channel: String,
        osFamily: String,
        appVersion: String,
        buildNumber: String,
        releaseChannel: String,
        serverUrl: String,
        pollIntervalMs: Int = 5000,
        maxBreadcrumbs: Int = 100,
        captureConsole: Bool = true,
        captureErrors: Bool = true,
        captureNetwork: Bool = true,
        getAuthToken: (@Sendable () async throws -> String)? = nil
    ) {
        self.productId = productId
        self.userId = userId
        self.anonymousInstallId = anonymousInstallId
        self.platform = platform
        self.channel = channel
        self.osFamily = osFamily
        self.appVersion = appVersion
        self.buildNumber = buildNumber
        self.releaseChannel = releaseChannel
        self.serverUrl = serverUrl
        self.pollIntervalMs = pollIntervalMs
        self.maxBreadcrumbs = maxBreadcrumbs
        self.captureConsole = captureConsole
        self.captureErrors = captureErrors
        self.captureNetwork = captureNetwork
        self.getAuthToken = getAuthToken
    }
}

/// Logger protocol
public protocol DiagnosticsLogger: Sendable {
    func debug(_ message: String, metadata: [String: any Sendable]?)
    func info(_ message: String, metadata: [String: any Sendable]?)
    func warn(_ message: String, metadata: [String: any Sendable]?)
    func error(_ message: String, metadata: [String: any Sendable]?)
}

/// Default no-op logger
public struct NoOpDiagnosticsLogger: DiagnosticsLogger {
    public init() {}
    public func debug(_ message: String, metadata: [String: any Sendable]?) {}
    public func info(_ message: String, metadata: [String: any Sendable]?) {}
    public func warn(_ message: String, metadata: [String: any Sendable]?) {}
    public func error(_ message: String, metadata: [String: any Sendable]?) {}
}

/// OSLog-based logger
public struct OSDiagnosticsLogger: DiagnosticsLogger {
    private let subsystem: String
    private let category: String
    private let logger: Logger

    public init(subsystem: String = "com.bytelyst.diagnostics", category: String = "DiagnosticsClient") {
        self.subsystem = subsystem
        self.category = category
        self.logger = Logger(subsystem: subsystem, category: category)
    }

    public func debug(_ message: String, metadata: [String: any Sendable]?) {
        #if DEBUG
        logger.debug("\(message, privacy: .public)")
        #endif
    }

    public func info(_ message: String, metadata: [String: any Sendable]?) {
        logger.info("\(message, privacy: .public)")
    }

    public func warn(_ message: String, metadata: [String: any Sendable]?) {
        logger.warning("\(message, privacy: .public)")
    }

    public func error(_ message: String, metadata: [String: any Sendable]?) {
        logger.error("\(message, privacy: .public)")
    }
}
