import UIKit

// MARK: - AdTimingInput

/// 广告各阶段时间戳，单位：毫秒（ms）
///
/// ObjC 使用：`[[AdTimingInput alloc] initWithRequestTimeMs:req fillTimeMs:fill showTimeMs:show]`
@objcMembers
public final class AdTimingInput: NSObject {

    /// 广告请求时间戳（毫秒）
    public let requestTimeMs: Int64
    /// 广告填充时间戳（毫秒）
    public let fillTimeMs: Int64
    /// 广告展示时间戳（毫秒）
    public let showTimeMs: Int64

    public init(requestTimeMs: Int64, fillTimeMs: Int64, showTimeMs: Int64) {
        self.requestTimeMs = requestTimeMs
        self.fillTimeMs    = fillTimeMs
        self.showTimeMs    = showTimeMs
        super.init()
    }

    /// 工厂方法：三个时间戳相同的简化场景（如 Demo 或无精确时间戳时）
    public static func sameWallClockMs(_ now: Int64) -> AdTimingInput {
        AdTimingInput(requestTimeMs: now, fillTimeMs: now, showTimeMs: now)
    }
}

// MARK: - FrameOptions

/// 截图采集选项
///
/// ObjC 默认构造：`[[FrameOptions alloc] init]`（使用所有默认值）
@objcMembers
public final class FrameOptions: NSObject {

    /// 截图延迟（ms），等待广告素材加载完成后再截图，默认 500ms
    public var delayMs: Int
    /// JPEG 压缩后最大文件大小（KB），默认 300KB
    public var maxSizeKb: Int
    /// 落盘 JPEG 最长边像素上限（按 `UIImage.size × scale` 判断并缩放），默认 1080px（对齐 Android 2160px 在 @2x 屏上的逻辑宽度）
    public var maxLongEdge: Int
    /// `true` = 优先保证质量（从 0.7 降质量直至满足大小约束）
    public var keepQualityFirst: Bool
    /// 截图时需要遮盖的视图（如密码输入框、隐私区域）
    public var excludeViews: [UIView]

    /// Swift 全参数初始化（含默认值）
    public init(
        delayMs: Int           = 500,
        maxSizeKb: Int         = 300,
        maxLongEdge: Int       = 1080,
        keepQualityFirst: Bool = true,
        excludeViews: [UIView] = []
    ) {
        self.delayMs          = delayMs
        self.maxSizeKb        = maxSizeKb
        self.maxLongEdge      = maxLongEdge
        self.keepQualityFirst = keepQualityFirst
        self.excludeViews     = excludeViews
        super.init()
    }

    /// ObjC 默认无参构造（所有字段取默认值）
    @objc public convenience override init() {
        self.init(delayMs: 500, maxSizeKb: 300, maxLongEdge: 1080,
                  keepQualityFirst: true, excludeViews: [])
    }
}

// MARK: - FrameRecord

/// 一次截图采集结果，代表一个持久化到沙盒的上传任务
@objcMembers
public final class FrameRecord: NSObject {

    /// 广告展示唯一标识（等同于 MMAdInfo.showId，用于服务端幂等去重）
    public let showId: String
    /// 上传任务唯一标识（SDK 内部生成 UUID）
    public let uploadTaskId: String
    /// 广告位 ID
    public let placementId: String
    /// 广告样式（Swift 专属；ObjC 请使用 `adType`）
    @nonobjc public let style: MaterialStyle
    /// 广告类型整数值（ObjC 友好，等同于 `style.adType`）
    @objc public var adType: Int { style.adType }
    /// 广告请求时间戳（毫秒）
    public let requestTimeMs: Int64
    /// 广告填充时间戳（毫秒）
    public let fillTimeMs: Int64
    /// 广告展示时间戳（毫秒）
    public let showTimeMs: Int64
    /// 原生广告素材原始 URL（仅原生自渲染场景传入）
    public let imageUrl: String?
    /// 图片在沙盒中的绝对路径
    public let localFilePath: String
    /// pHash 值（16 字符小写 hex）
    public let imageHash: String
    /// 采集时间戳（毫秒）
    public let createdAt: Int64

    public init(
        showId: String, uploadTaskId: String, placementId: String,
        style: MaterialStyle,
        requestTimeMs: Int64, fillTimeMs: Int64, showTimeMs: Int64,
        imageUrl: String?    = nil,
        localFilePath: String, imageHash: String, createdAt: Int64
    ) {
        self.showId        = showId
        self.uploadTaskId  = uploadTaskId
        self.placementId   = placementId
        self.style         = style
        self.requestTimeMs = requestTimeMs
        self.fillTimeMs    = fillTimeMs
        self.showTimeMs    = showTimeMs
        self.imageUrl      = imageUrl
        self.localFilePath = localFilePath
        self.imageHash     = imageHash
        self.createdAt     = createdAt
        super.init()
    }
}

// MARK: - MMAdInfo

/// 广告信息，由业务方在 onAdShow 回调中构造并传入 MaterialMonitor SDK
///
/// `adType` 直接传入 TopOn 回调 extra 中 `kATADDelegateExtraADSourceTypeKey` 对应的整数值。
/// 对应 ATAdFormat 枚举：0=Native / 1=RewardedVideo / 2=Banner / 3=Interstitial / 4=Splash
///
/// ObjC 构造示例：
/// ```objc
/// NSInteger adType = [extra[kATADDelegateExtraADSourceTypeKey] integerValue];
/// MMAdInfo *info = [[MMAdInfo alloc]
///   initWithRequestId:@"req_id" showId:@"show_id" placementId:@"p_id"
///   adSourceId:@"src_id" adNetworkFirmId:0 adType:adType
///   requestTimestamp:reqTs fillTimestamp:fillTs showTimestamp:showTs
///   creativeId:nil ecpm:nil sceneId:nil];
/// ```
@objcMembers
public final class MMAdInfo: NSObject {

    // MARK: 必填
    /// 请求 ID
    public let requestId: String
    /// 广告展示唯一 ID（服务端幂等去重）
    public let showId: String
    /// 广告位 ID
    public let placementId: String
    /// 广告源 ID
    public let adSourceId: String
    /// 广告网络 ID
    public let adNetworkFirmId: Int
    /// 广告类型整数，来自 TopOn 回调 extra[kATADDelegateExtraADSourceTypeKey]
    /// 对应 ATAdFormat：0=Native / 1=RewardedVideo / 2=Banner / 3=Interstitial / 4=Splash
    public let adType: Int
    /// 广告请求时间戳（毫秒）
    public let requestTimestamp: Int64
    /// 广告填充时间戳（毫秒）
    public let fillTimestamp: Int64
    /// 广告展示时间戳（毫秒）
    public let showTimestamp: Int64

    // MARK: 选填
    /// 创意 ID（部分广告网络不返回，传 nil 时上报空字符串）
    public let creativeId: String?
    /// eCPM（使用 NSNumber 以兼容 ObjC；Swift 可传 `2.5 as NSNumber` 或 `nil`）
    public let ecpm: NSNumber?
    /// 场景 ID
    public let sceneId: String?

    /// SDK 内部使用：adType 整数 → MaterialStyle.rawValue 字符串
    /// 不对外暴露，外部请使用 adType
    var format: String { MaterialStyle(adType: adType)?.rawValue ?? "" }

    public init(
        requestId: String, showId: String, placementId: String,
        adSourceId: String, adNetworkFirmId: Int, adType: Int,
        requestTimestamp: Int64, fillTimestamp: Int64, showTimestamp: Int64,
        creativeId: String? = nil, ecpm: NSNumber? = nil, sceneId: String? = nil
    ) {
        self.requestId        = requestId
        self.showId           = showId
        self.placementId      = placementId
        self.adSourceId       = adSourceId
        self.adNetworkFirmId  = adNetworkFirmId
        self.adType           = adType
        self.requestTimestamp = requestTimestamp
        self.fillTimestamp    = fillTimestamp
        self.showTimestamp    = showTimestamp
        self.creativeId       = creativeId
        self.ecpm             = ecpm
        self.sceneId          = sceneId
        super.init()
    }
}
