import SwiftUI
import PhotosUI

/// 处理图片上传到远程服务器的类
/// 支持上传图片并获取服务器返回的file_id
public class ImageUploaderGetID: ObservableObject {
    // MARK: - 类型定义
    
    /// 上传结果
    public struct UploadResult: Codable {
        public let fileUrl: String
        public let fileName: String
        public let fileSize: Int
        public let fileId: String
        
        public init(fileUrl: String, fileName: String, fileSize: Int, fileId: String) {
            self.fileUrl = fileUrl
            self.fileName = fileName
            self.fileSize = fileSize
            self.fileId = fileId
        }
    }
    
    /// 上传过程中可能发生的错误
    public enum UploadError: LocalizedError {
        case invalidImageData
        case invalidURL
        case serverError(String)
        case invalidResponse
        case uploadFailed(Error?)
        case invalidFileId
        case invalidResponseData
        
        public var errorDescription: String? {
            switch self {
            case .invalidImageData:
                return "无效的图片数据"
            case .invalidURL:
                return "无效的URL"
            case .serverError(let message):
                return "服务器错误: \(message)"
            case .invalidResponse:
                return "无效的服务器响应"
            case .uploadFailed(let error):
                return "上传失败: \(error?.localizedDescription ?? "未知错误")"
            case .invalidFileId:
                return "无效的文件ID"
            case .invalidResponseData:
                return "无效的响应数据"
            }
        }
    }
    
    // MARK: - 属性
    
    private let session: URLSession
    private let apiConfig: APIConfig.Type
    
    // MARK: - 初始化方法
    
    /// 初始化方法
    /// - Parameters:
    ///   - session: 可选的URLSession，用于测试依赖注入
    ///   - apiConfig: 可选的API配置，用于测试依赖注入
    public init(session: URLSession = .shared, apiConfig: APIConfig.Type = APIConfig.self) {
        self.session = session
        self.apiConfig = apiConfig
    }
    
    // MARK: - 公开方法
    
    /// 上传图片到服务器
    /// - Parameters:
    ///   - image: 要上传的图片
    ///   - progress: 上传进度回调 (0.0 到 1.0)
    ///   - completion: 完成回调
    public func uploadImage(
        _ image: UIImage,
        progress: @escaping (Double) -> Void,
        completion: @escaping (Result<UploadResult, Error>) -> Void
    ) {
        print("🔄 开始准备上传图片...")
        
        // 1. 转换图片为Data
        guard let imageData = image.jpegData(compressionQuality: 0.7) else {
            let error = UploadError.invalidImageData
            print("❌ 错误：\(error.localizedDescription)")
            completion(.failure(error))
            return
        }
        
        // 2. 获取上传URL
        getUploadURL(for: imageData) { [weak self] result in
            switch result {
            case .success((let fileId, let uploadURL)):
                print("📤 获取到上传URL，开始上传文件...")
                
                // 3. 上传文件
                _ = self?.uploadFile(
                    fileData: imageData,
                    to: uploadURL,
                    mimeType: "image/jpeg",
                    onProgress: { uploadProgress in
                        print("📊 上传进度: \(Int(uploadProgress * 100))%")
                        progress(uploadProgress)
                    },
                    completion: { uploadResult in
                        switch uploadResult {
                        case .success:
                            // 4. 确认上传
                            self?.confirmUpload(
                                fileId: fileId,
                                fileName: "avatar_\(UUID().uuidString).jpg",
                                fileSize: imageData.count,
                                completion: completion
                            )
                            
                        case .failure(let error):
                            print("❌ 文件上传失败: \(error.localizedDescription)")
                            completion(.failure(error))
                        }
                    }
                )
                
            case .failure(let error):
                print("❌ 获取上传URL失败: \(error.localizedDescription)")
                completion(.failure(error))
            }
        }
    }
    
    // MARK: - Video Upload
    
    /// 上传视频文件到服务器
    /// - Parameters:
    ///   - videoURL: 要上传的视频文件URL
    ///   - progress: 上传进度回调 (0.0 到 1.0)
    ///   - completion: 完成回调
    public func uploadVideo(
        _ videoURL: URL,
        progress: @escaping (Double) -> Void,
        completion: @escaping (Result<UploadResult, Error>) -> Void
    ) {
        print("🔄 开始准备上传视频...")
        
        // 1. 读取视频文件数据
        do {
            let videoData = try Data(contentsOf: videoURL)
            let fileExtension = videoURL.pathExtension.lowercased()
            let mimeType: String
            
            // 根据文件扩展名设置MIME类型
            switch fileExtension {
            case "mp4":
                mimeType = "video/mp4"
            case "mov":
                mimeType = "video/quicktime"
            case "m4v":
                mimeType = "video/x-m4v"
            case "avi":
                mimeType = "video/x-msvideo"
            default:
                mimeType = "video/mp4" // 默认使用mp4
            }
            
            // 2. 获取上传URL
            getUploadURL(for: videoData, mimeType: mimeType, originalFilename: videoURL.lastPathComponent) { [weak self] result in
                switch result {
                case .success((let fileId, let uploadURL)):
                    print("📤 获取到视频上传URL，开始上传文件...")
                    
                    // 3. 上传文件
                    _ = self?.uploadFile(
                        fileData: videoData,
                        to: uploadURL,
                        mimeType: mimeType,
                        onProgress: progress,
                        completion: { result in
                            switch result {
                            case .success:
                                // 4. 确认上传完成
                                self?.confirmUpload(
                                    fileId: fileId,
                                    fileName: videoURL.lastPathComponent,
                                    fileSize: videoData.count,
                                    completion: completion
                                )
                            case .failure(let error):
                                completion(.failure(error))
                            }
                        }
                    )
                    
                case .failure(let error):
                    completion(.failure(error))
                }
            }
        } catch {
            print("❌ 读取视频文件失败: \(error.localizedDescription)")
            completion(.failure(error))
        }
    }
    
    // MARK: - 私有方法
    
    /// 获取上传URL
    private func getUploadURL(for imageData: Data, completion: @escaping (Result<(fileId: String, uploadURL: URL), Error>) -> Void) {
        let fileName = "avatar_\(UUID().uuidString).jpg"
        let parameters: [String: Any] = [
            "filename": fileName,
            "content_type": "image/jpeg",
            "file_size": imageData.count
        ]
        
        let urlString = "\(apiConfig.baseURL)/file/generate-upload-url"
        guard let url = URL(string: urlString) else {
            completion(.failure(UploadError.invalidURL))
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.allHTTPHeaderFields = apiConfig.authHeaders
        
        do {
            request.httpBody = try JSONSerialization.data(withJSONObject: parameters)
            print("📤 准备上传请求，文件名: \(fileName), 大小: \(Double(imageData.count) / 1024.0) KB")
        } catch {
            print("❌ 序列化请求参数失败: \(error.localizedDescription)")
            completion(.failure(error))
            return
        }
        
        let task = session.dataTask(with: request) { data, response, error in
            if let error = error {
                completion(.failure(UploadError.uploadFailed(error)))
                return
            }
            
            guard let httpResponse = response as? HTTPURLResponse else {
                completion(.failure(UploadError.invalidResponse))
                return
            }
            
            guard let data = data else {
                completion(.failure(UploadError.invalidResponse))
                return
            }
            
            // 打印调试信息
            if let responseString = String(data: data, encoding: .utf8) {
                print("📥 获取上传URL响应: \(responseString)")
            }
            
            do {
                guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
                      let dataDict = json["data"] as? [String: Any],
                      let fileId = dataDict["file_id"] as? String,
                      let uploadURLString = dataDict["upload_url"] as? String,
                      let uploadURL = URL(string: uploadURLString) else {
                    throw UploadError.invalidResponse
                }
                
                completion(.success((fileId: fileId, uploadURL: uploadURL)))
            } catch {
                completion(.failure(UploadError.invalidResponse))
            }
        }
        
        task.resume()
    }
    
    /// 获取上传URL
    /// - Parameters:
    ///   - fileData: 要上传的文件数据
    ///   - mimeType: 文件MIME类型
    ///   - originalFilename: 原始文件名
    ///   - completion: 完成回调
    private func getUploadURL(
        for fileData: Data,
        mimeType: String,
        originalFilename: String? = nil,
        completion: @escaping (Result<(fileId: String, uploadURL: URL), Error>) -> Void
    ) {
        let fileName = originalFilename ?? "file_\(UUID().uuidString)"
        let parameters: [String: Any] = [
            "filename": fileName,
            "content_type": mimeType,
            "file_size": fileData.count
        ]
        
        let urlString = "\(apiConfig.baseURL)/file/generate-upload-url"
        guard let url = URL(string: urlString) else {
            completion(.failure(UploadError.invalidURL))
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.allHTTPHeaderFields = apiConfig.authHeaders
        
        do {
            request.httpBody = try JSONSerialization.data(withJSONObject: parameters)
            print("📤 准备上传请求，文件名: \(fileName), 大小: \(Double(fileData.count) / 1024.0) KB")
        } catch {
            print("❌ 序列化请求参数失败: \(error.localizedDescription)")
            completion(.failure(error))
            return
        }
        
        let task = session.dataTask(with: request) { data, response, error in
            if let error = error {
                completion(.failure(UploadError.uploadFailed(error)))
                return
            }
            
            guard let httpResponse = response as? HTTPURLResponse else {
                completion(.failure(UploadError.invalidResponse))
                return
            }
            
            guard let data = data else {
                completion(.failure(UploadError.invalidResponse))
                return
            }
            
            // 打印调试信息
            if let responseString = String(data: data, encoding: .utf8) {
                print("📥 上传URL响应: \(responseString)")
            }
            
            do {
                let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
                guard let code = json?["code"] as? Int, code == 0,
                      let dataDict = json?["data"] as? [String: Any],
                      let fileId = dataDict["file_id"] as? String,
                      let uploadURLString = dataDict["upload_url"] as? String,
                      let uploadURL = URL(string: uploadURLString) else {
                    throw UploadError.invalidResponse
                }
                
                completion(.success((fileId: fileId, uploadURL: uploadURL)))
            } catch {
                completion(.failure(UploadError.invalidResponse))
            }
        }
        
        task.resume()
    }
    
    /// 确认上传
    private func confirmUpload(fileId: String, fileName: String, fileSize: Int, completion: @escaping (Result<UploadResult, Error>) -> Void) {
        let endpoint = "\(apiConfig.baseURL)/file/confirm-upload"
        guard let url = URL(string: endpoint) else {
            completion(.failure(UploadError.invalidURL))
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.allHTTPHeaderFields = apiConfig.authHeaders
        
        let body: [String: Any] = [
            "file_id": fileId,
            "file_name": fileName,
            "file_size": fileSize
        ]
        
        do {
            request.httpBody = try JSONSerialization.data(withJSONObject: body)
            print("📤 确认上传请求，fileId: \(fileId), 文件名: \(fileName)")
        } catch {
            print("❌ 序列化确认上传参数失败: \(error.localizedDescription)")
            completion(.failure(error))
            return
        }
        
        let task = session.dataTask(with: request) { data, response, error in
            if let error = error {
                print("❌ 确认上传请求失败: \(error.localizedDescription)")
                completion(.failure(UploadError.uploadFailed(error)))
                return
            }
            
            guard let httpResponse = response as? HTTPURLResponse else {
                print("❌ 无效的服务器响应")
                completion(.failure(UploadError.invalidResponse))
                return
            }
            
            guard (200...299).contains(httpResponse.statusCode) else {
                let statusCode = httpResponse.statusCode
                let errorMessage = "确认上传失败，状态码: \(statusCode)"
                print("❌ \(errorMessage)")
                completion(.failure(UploadError.serverError(errorMessage)))
                return
            }
            
            // 创建上传结果
            let uploadResult = UploadResult(
                fileUrl: "\(self.apiConfig.baseURL)/files/\(fileId)",
                fileName: fileName,
                fileSize: fileSize,
                fileId: fileId
            )
            
            print("✅ 图片上传并确认成功，fileId: \(fileId)")
            completion(.success(uploadResult))
        }
        
        task.resume()
    }
    
    /// 上传文件到指定URL
    /// - Parameters:
    ///   - fileData: 要上传的文件数据
    ///   - uploadURL: 上传URL
    ///   - mimeType: 文件MIME类型
    ///   - onProgress: 进度回调，0.0 到 1.0
    ///   - completion: 完成回调
    public func uploadFile(
        fileData: Data,
        to uploadURL: URL,
        mimeType: String = "application/octet-stream",
        onProgress: @escaping (Double) -> Void,
        completion: @escaping (Result<Void, Error>) -> Void
    ) -> URLSessionUploadTask {
        var request = URLRequest(url: uploadURL)
        request.httpMethod = "PUT"
        request.setValue(mimeType, forHTTPHeaderField: "Content-Type")
        
        let task = session.uploadTask(
            with: request,
            from: fileData
        ) { _, response, error in
            if let error = error {
                completion(.failure(error))
                return
            }
            
            guard let httpResponse = response as? HTTPURLResponse else {
                completion(.failure(UploadError.invalidResponse))
                return
            }
            
            guard httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 else {
                let statusCode = httpResponse.statusCode
                completion(.failure(UploadError.serverError("上传失败，状态码: \(statusCode)")))
                return
            }
            
            completion(.success(()))
        }
        
        // 添加进度观察
        if #available(iOS 11.0, *) {
            let progressObserver = task.progress.observe(\.fractionCompleted) { (progressValue, _) in
                DispatchQueue.main.async {
                    onProgress(progressValue.fractionCompleted)
                }
            }
            
            task.addCompletionHandler { [weak task] in
                progressObserver.invalidate()
                task?.progress.cancel()
            }
        } else {
            // iOS 11 以下版本使用通知
            var lastProgress: Double = 0
            let timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
                let bytesSent = task.countOfBytesSent
                let totalBytes = task.countOfBytesExpectedToSend
                let currentProgress = totalBytes > 0 ? Double(bytesSent) / Double(totalBytes) : 0
                
                // 只有当进度有显著变化时才回调，避免频繁更新UI
                if abs(currentProgress - lastProgress) > 0.01 || currentProgress >= 1.0 {
                    lastProgress = currentProgress
                    DispatchQueue.main.async {
                        onProgress(min(currentProgress, 1.0))
                    }
                }
                
                if currentProgress >= 1.0 {
                    timer.invalidate()
                }
            }
            
            task.addCompletionHandler {
                timer.invalidate()
            }
        }
        
        task.resume()
        return task
    }
    
    // MARK: - 文件上传状态
    
    /// 文件上传状态
    public struct FileStatus {
        public let file: Data
        public var status: UploadStatus
        public var progress: Double
        
        public enum UploadStatus {
            case pending
            case uploading
            case completed
            case failed(Error)
        }
        
        public init(file: Data, status: UploadStatus = .pending, progress: Double = 0) {
            self.file = file
            self.status = status
            self.progress = progress
        }
    }
}

// MARK: - URLSessionTask 扩展

private class TaskObserver: NSObject {
    private weak var task: URLSessionTask?
    private var handlers: [() -> Void] = []
    
    init(task: URLSessionTask) {
        self.task = task
        super.init()
        task.addObserver(self, forKeyPath: #keyPath(URLSessionTask.state), options: .new, context: nil)
    }
    
    func addHandler(_ handler: @escaping () -> Void) {
        handlers.append(handler)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard keyPath == #keyPath(URLSessionTask.state),
              let task = task,
              task.state == .completed else {
            return
        }
        
        // 调用所有完成处理器
        DispatchQueue.main.async { [weak self] in
            self?.handlers.forEach { $0() }
            self?.cleanup()
        }
    }
    
    private func cleanup() {
        task?.removeObserver(self, forKeyPath: #keyPath(URLSessionTask.state))
        handlers.removeAll()
    }
    
    deinit {
        cleanup()
    }
}

private extension URLSessionTask {
    private static var taskObserverKey: UInt8 = 0
    
    private var taskObserver: TaskObserver? {
        get {
            return objc_getAssociatedObject(self, &Self.taskObserverKey) as? TaskObserver
        }
        set {
            objc_setAssociatedObject(self, &Self.taskObserverKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    func addCompletionHandler(_ handler: @escaping () -> Void) {
        if #available(iOS 11.0, *) {
            if let observer = taskObserver {
                observer.addHandler(handler)
            } else {
                let observer = TaskObserver(task: self)
                observer.addHandler(handler)
                taskObserver = observer
            }
        } else {
            // iOS 11 以下版本使用通知
            let name = NSNotification.Name("TaskCompleted\(self.taskIdentifier)")
            NotificationCenter.default.addObserver(
                forName: name,
                object: self,
                queue: .main
            ) { _ in
                handler()
            }
        }
    }
}

// MARK: - 响应模型

struct UploadURLResponse: Codable {
    let code: Int
    let message: String
    let data: UploadData
    
    struct UploadData: Codable {
        let fileId: String
        let uploadUrl: String
        
        enum CodingKeys: String, CodingKey {
            case fileId = "file_id"
            case uploadUrl = "upload_url"
        }
    }
}
