//
//  UploadModels.swift

//
//  Created by Leon on 2025/7/21.
//

import Foundation
import AWSS3

// MARK: - Protocols

protocol UploadPhotoCallBackProtocol {
    func mm_uploadProgress(_ progress: Float)
    func mm_uploadFailed()
    func mm_uploadDone(_ remoteImageUrlString: String)
}

protocol UploadPhotoDelegate: AnyObject {
    
//    func uploadFail()
//    func uploadDone()
    func uploadDoneWith(_ photo: UploadPhotoM)
    func uploadFailWith(_ photo: UploadPhotoM)
    func uploadProgress(_ progress: Float)
    func imageCheck(_ photoM: UploadPhotoM, result: Bool)
//    func imageIdentyReal(_ photo: UploadPhotoM, result: Bool)
//    func imageIdentifyChild(_ photo: UploadPhotoM, result: Bool)
//    func imageFullCheck(_ photo: UploadPhotoM, nfswCheck: Bool, realPersonCheck: Bool)
//    func imageFullCheck(_ photo: UploadPhotoM, nfswCheck: Bool, childCheck: Bool)
}

protocol UploadModelDelegate: AnyObject {
    
    func uploadFail()
    func uploadDone()
    func uploadDoneWith(_ photo: UploadModel)
    func uploadFailWith(_ photo: UploadModel)
    func uploadProgress(_ progress: Float)
}

// MARK: - UploadEntity

class UploadEntity: NSObject, UploadPhotoCallBackProtocol {
    func mm_uploadProgress(_ progress: Float) {
        
    }
    
    func mm_uploadFailed() {
        
    }
    
    func mm_uploadDone(_ remoteImageUrlString: String) {
        
    }
    
    weak var utility: AWSS3TransferUtility?
    var addThisItemTimeStamp: Int = 0
    var uploadProgress: Float = 0.0
    var isFailed: Bool = false
    var isDone: Bool = false
    var isUploading: Bool = false
}

// MARK: - UploadModel

class UploadModel: UploadEntity {
    var fileData: Data?
    var s3AuthData: S3AuthData?
    /// 一般是不含域名的部分链接
    var remoteImageUrlString: String?
    var remoteFullPath: String?
    weak var delegate: UploadModelDelegate?
    
    func suffix() -> String {
        return ".mp3"
    }
    
    func contentType() -> String {
        return "audio/mp3"
    }
    
    func releaseS3Utility() {
        if let utility = utility, let _ = s3AuthData?.fileName {
            //#warning("Confirm")
            //AWSS3TransferUtility.removeS3TransferUtility(forKey: fileName)
            utility.cancelAll()
        }
    }
    
    // MARK: - Setter Overrides
    override var uploadProgress: Float {
        get { super.uploadProgress }
        set {
            super.uploadProgress = newValue
            delegate?.uploadProgress(newValue)
        }
    }
    
    override var isDone: Bool {
        get { super.isDone }
        set {
            super.isDone = newValue
            delegate?.uploadDoneWith(self)
            delegate?.uploadDone()
        }
    }
    
    override var isFailed: Bool {
        get { super.isFailed }
        set {
            super.isFailed = newValue
            delegate?.uploadFailWith(self)
            delegate?.uploadFail()
        }
    }
    
    // MARK: - UploadPhotoCallBackProtocol
    override func mm_uploadProgress(_ progress: Float) {
        self.uploadProgress = progress
    }
    
    override func mm_uploadFailed() {
        releaseS3Utility()
        isFailed = true
        isUploading = false
    }
    
    override func mm_uploadDone(_ remoteImageUrlString: String) {
        releaseS3Utility()
        self.remoteImageUrlString = remoteImageUrlString
        isDone = true
        isUploading = false
    }
}

// MARK: - UploadPhotoM

class UploadPhotoM: UploadEntity {
    weak var delegate: UploadPhotoDelegate?
    
    // MARK: Data
    var image: UIImage?{
        didSet{
            if image?.size.width ?? 0 > 0 && image?.size.height ?? 0 > 0{
                imageSize = image!.pixelSize
            }
        }
    }
    var imageData: Data?
    var bucketEnum: BucketS3Enum = .UNKNOW
    var s3AuthData: S3AuthData?
    /// 一般是不含域名的部分链接
    var remoteImageUrlString: String?
    /// 文件全路径、含域名
    var remoteFullPath: String?
    var imageSize: CGSize = .zero
    var suffixEnum: SuffixS3Enum = .jpeg
    
    // MARK: Config
    /// -- Config: Default true: 默认需要鉴黄
    var isAutoCheckImage: Bool = true
    var isHideCheckToast: Bool = false
    
    // MARK: State
    private(set) var imageCheckIsViolation: Bool = false
    /// Default false
    private(set) var imageChecked: Bool = false
    private(set) var isOverSizeLimmit: Bool = false
    private(set) var errorMsg: String?
    var imageFrame: CGRect = .zero
    var isEditMode: Bool = false
    
    
    // MARK: Inner methods
    /// true: 禁止在delegate(UploadPhotoDelegate)回调中鉴黄。 在CloudStorage中block判断和鉴黄。自动管理，上传时不需要设置
    var banCheckImageInDelegateMethod: Bool = false
    
    override init() {
        super.init()
        suffixEnum = .jpeg
    }
    
    // MARK: - Public Methods
    func getFullUrlString() -> String {
        if let fullUrl = remoteFullPath, fullUrl.count >  0 {
            return fullUrl
        }else if let remoteImageFull = remoteImageUrlString{
            return remoteImageFull // .fullUrlFromRelativePath // ⚠️这个路径不是全路径，需要拼接一个域名，暂时不会走到此分支！
        }
        return ""
    }
    
    func setupValidImageUrl(url: String?){
        guard let imgUrl = url else{return}
        remoteFullPath = imgUrl
        isDone = true
        imageChecked = true
        addThisItemTimeStamp = Date().timeStamp
    }
    
    /// block返回 false，表示不是黄图
    func checkImageOK(_ block: ((Bool) -> Void)? = nil) {
        guard let tempPath = remoteImageUrlString, tempPath.isNotBlank else {
            assert(false)
            block?(false)
            return
        }
        
        OssProvider.request(.nsfwCheck(fileFullPath: tempPath, s3BucketEnum: bucketEnum.rawValue), modelType: Bool.self) {[weak self] result in
            guard let `self` = self else {
                return
            }
            self.isUploading = false
            switch result {
            case let .success(checkResult):
                self.imageChecked = true
                //self.realateUrlAdpatEPalAddSlash(add: true)
                let nsfw = checkResult ?? true
                let imgOk = !nsfw
                self.delegate?.imageCheck(self, result: imgOk)
                block?(imgOk)
            case let .failure(error):
                switch error {
                case let .serviceError(code, msg):
                    if code == .imageCheckFailed{
                        self.imageChecked = true
                        self.imageCheckIsViolation = true
                        self.errorMsg = msg
                        self.delegate?.imageCheck(self, result: false)
                    }else{
                        self.imageCheckIsViolation = false
                        self.isFailed = true
                        self.isDone = false
                        self.delegate?.imageCheck(self, result: false)
                    }
                default:
                    break
                }
                block?(false)
            }
        }
    }
    
    func contentType() -> String {
        switch suffixEnum {
        case .gif: return "image/gif"
        case .png: return "image/png"
        default: return "image/jpeg"
        }
    }
    
    func releaseS3Utility() {
        if let utility = utility {
            //AWSS3TransferUtility.removeS3TransferUtility(forKey: fileName)
            utility.cancelAll()
        }
    }
    
    func setupPhotoOversizeLimmit() {
        isOverSizeLimmit = true
    }
    
    func setupErrorMsg(_ msg: String) {
        errorMsg = msg
    }
    
    // MARK: - Setter Overrides
    override var uploadProgress: Float {
        get { super.uploadProgress }
        set {
            super.uploadProgress = newValue
            delegate?.uploadProgress(newValue)
        }
    }
    
    override var isDone: Bool {
        get { super.isDone }
        set {
            super.isDone = newValue
            delegate?.uploadDoneWith(self)
//            delegate?.uploadDone()
        }
    }
    
    override var isFailed: Bool {
        get { super.isFailed }
        set {
            super.isFailed = newValue
            delegate?.uploadFailWith(self)
//            delegate?.uploadFail()
        }
    }
    
    // MARK: - UploadPhotoCallBackProtocol
    override func mm_uploadProgress(_ progress: Float) {
        self.uploadProgress = progress
    }
    
    override func mm_uploadFailed() {
        releaseS3Utility()
        isFailed = true
        isUploading = false
    }
    
    override func mm_uploadDone(_ remoteImageUrlString: String) {
        releaseS3Utility()
        self.remoteImageUrlString = remoteImageUrlString
        isDone = true
        
        if isAutoCheckImage {
            if !banCheckImageInDelegateMethod {
                checkImageOK(nil)
            }
        } else {
            isUploading = false
            realateUrlAdpatEPalAddSlash(add: true)
        }
    }
    
    // MARK: - Helper
    @discardableResult
    private func realateUrlAdpatEPalAddSlash(add: Bool) -> String {
        var url = remoteImageUrlString ?? ""
        if add {
            if !url.isEmpty && !url.hasPrefix("/") {
                url = "/\(url)"
            }
        } else {
            if !url.isEmpty && url.hasPrefix("/") {
                url.removeFirst()
            }
        }
        remoteImageUrlString = url
        return url
    }
}
