import Foundation
import ImageCaptureCore

/// PTP 容器类型。
enum PTPContainerType: UInt16 {
    case command = 0x0001
    case data = 0x0002
    case response = 0x0003
    case event = 0x0004
}

/// PTP 命令/响应/事件容器。
struct PTPContainer {
    let length: UInt32
    let type: UInt16
    let code: UInt16
    let transactionID: UInt32
    let params: [UInt32]
}

enum PTPParseError: Error {
    case tooShort
    case invalidLength
}

/// 标准 PTP 响应码。
enum PTPResponseCode: UInt16 {
    case ok = 0x2001
    case generalError = 0x2002
    case sessionNotOpen = 0x2003
    case invalidTransaction = 0x2004
    case operationNotSupported = 0x2005
}

/// PTP 命令发送结果。
struct PTPCommandResult {
    let success: Bool
    let response: Data
    let inData: Data
}

/// 各品牌共用的 PTP 编解码与命令发送工具。
enum PTPHelper {
    static func buildCommand(
        code: UInt16,
        transactionID: UInt32,
        parameters: [UInt32] = []
    ) -> Data {
        let length = UInt32(12 + parameters.count * 4)
        var data = Data()
        appendUInt32LE(length, to: &data)
        appendUInt16LE(PTPContainerType.command.rawValue, to: &data)
        appendUInt16LE(code, to: &data)
        appendUInt32LE(transactionID, to: &data)
        for parameter in parameters {
            appendUInt32LE(parameter, to: &data)
        }
        return data
    }

    static func parseContainer(_ data: Data) throws -> PTPContainer {
        guard data.count >= 12 else { throw PTPParseError.tooShort }

        let length = readUInt32LE(data, offset: 0)
        guard length >= 12, data.count >= Int(length) else { throw PTPParseError.invalidLength }

        let type = readUInt16LE(data, offset: 4)
        let code = readUInt16LE(data, offset: 6)
        let transactionID = readUInt32LE(data, offset: 8)

        var params: [UInt32] = []
        var offset = 12
        while offset + 4 <= Int(length) {
            params.append(readUInt32LE(data, offset: offset))
            offset += 4
        }

        return PTPContainer(
            length: length,
            type: type,
            code: code,
            transactionID: transactionID,
            params: params
        )
    }

    static func parseEventCode(from eventData: Data) -> UInt16? {
        guard let container = try? parseContainer(eventData) else { return nil }
        return container.code
    }

    static func parseObjectCompressedSize(_ data: Data) -> UInt32? {
        guard data.count >= 12 else { return nil }
        return readUInt32LE(data, offset: 8)
    }

    static func parseObjectInfoFilename(_ data: Data) -> String? {
        guard data.count >= 53 else { return nil }

        if let filename = parsePTPString(data, offset: 52)?.string, !filename.isEmpty {
            return CameraDownloadStorage.sanitizeFilename(filename)
        }

        var offset = 52
        var codeUnits: [UInt16] = []
        while offset + 1 < data.count {
            let unit = readUInt16LE(data, offset: offset)
            if unit == 0 { break }
            codeUnits.append(unit)
            offset += 2
        }

        guard !codeUnits.isEmpty else { return nil }
        let raw = String(utf16CodeUnits: codeUnits, count: codeUnits.count)
        return CameraDownloadStorage.sanitizeFilename(raw)
    }

    static func parsePTPString(_ data: Data, offset start: Int) -> (string: String, nextOffset: Int)? {
        guard start < data.count else { return nil }
        let charCount = Int(data[start])
        var offset = start + 1
        guard charCount > 0, offset + charCount * 2 <= data.count else { return nil }

        var codeUnits: [UInt16] = []
        codeUnits.reserveCapacity(charCount)
        for index in 0..<charCount {
            codeUnits.append(readUInt16LE(data, offset: offset + index * 2))
        }
        offset += charCount * 2

        let string = String(utf16CodeUnits: codeUnits, count: codeUnits.count)
        return (string, offset)
    }

    static func isLikelyImageData(_ data: Data) -> Bool {
        guard data.count >= 3 else { return false }
        if data[0] == 0xFF, data[1] == 0xD8, data[2] == 0xFF { return true }
        if data.count >= 4, data[0] == 0x89, data[1] == 0x50, data[2] == 0x4E, data[3] == 0x47 { return true }
        return data.count > 1024
    }

    static func isResponseOK(_ response: Data) -> Bool {
        guard !response.isEmpty else { return true }
        guard let parsed = try? parseContainer(response) else { return false }
        return parsed.code == PTPResponseCode.ok.rawValue
    }

    /// 通过 ImageCaptureCore 发送 PTP 命令。
    static func sendCommand(
        on camera: ICCameraDevice,
        code: UInt16,
        transactionID: inout UInt32,
        parameters: [UInt32],
        outData: Data?,
        label: String
    ) async -> PTPCommandResult {
        let currentID = transactionID
        transactionID += 1

        let commandData = buildCommand(
            code: code,
            transactionID: currentID,
            parameters: parameters
        )

        return await withCheckedContinuation { continuation in
            camera.requestSendPTPCommand(
                commandData,
                outData: outData,
                completion: { inData, response, error in
                    if let error {
                        CameraTetheringLogger.log("PTP \(label) 失败: \(error.localizedDescription)", logger: CameraTetheringLogger.ptp)
                        continuation.resume(returning: PTPCommandResult(success: false, response: response, inData: inData))
                        return
                    }

                    var commandSuccess = true
                    if !response.isEmpty {
                        do {
                            let parsed = try parseContainer(response)
                            if parsed.code != PTPResponseCode.ok.rawValue {
                                CameraTetheringLogger.log(
                                    "PTP \(label) 响应码: 0x\(String(format: "%04X", parsed.code)) (非 OK)",
                                    logger: CameraTetheringLogger.ptp
                                )
                                commandSuccess = false
                            }
                        } catch {
                            CameraTetheringLogger.log("PTP \(label) 响应解析失败", logger: CameraTetheringLogger.ptp)
                            commandSuccess = false
                        }
                    }

                    if commandSuccess {
                        CameraTetheringLogger.log(
                            "PTP \(label) 成功, inData=\(inData.count) bytes",
                            logger: CameraTetheringLogger.ptp
                        )
                    }
                    continuation.resume(returning: PTPCommandResult(success: commandSuccess, response: response, inData: inData))
                }
            )
        }
    }

    static func appendUInt16LE(_ value: UInt16, to data: inout Data) {
        var littleEndian = value.littleEndian
        withUnsafeBytes(of: &littleEndian) { raw in
            data.append(contentsOf: raw)
        }
    }

    static func appendUInt32LE(_ value: UInt32, to data: inout Data) {
        var littleEndian = value.littleEndian
        withUnsafeBytes(of: &littleEndian) { raw in
            data.append(contentsOf: raw)
        }
    }

    static func readUInt16LE(_ data: Data, offset: Int) -> UInt16 {
        UInt16(data[offset])
            | (UInt16(data[offset + 1]) << 8)
    }

    static func readUInt32LE(_ data: Data, offset: Int) -> UInt32 {
        UInt32(data[offset])
            | (UInt32(data[offset + 1]) << 8)
            | (UInt32(data[offset + 2]) << 16)
            | (UInt32(data[offset + 3]) << 24)
    }
}
