package com.tt.honeyDue.util

import com.tt.honeyDue.platform.ImageData
import kotlinx.cinterop.*
import platform.Foundation.*
import platform.UIKit.*
import platform.posix.memcpy

/**
 * iOS implementation of image compression
 * Compresses images to JPEG format and ensures they don't exceed MAX_IMAGE_SIZE_BYTES
 */
@OptIn(ExperimentalForeignApi::class)
actual object ImageCompressor {
    /**
     * Compress an ImageData to JPEG format with size limit
     * @param imageData The image to compress
     * @return Compressed image data as ByteArray
     */
    actual fun compressImage(imageData: ImageData): ByteArray {
        // Convert ByteArray to NSData
        val nsData = imageData.bytes.usePinned { pinned ->
            NSData.create(
                bytes = pinned.addressOf(0),
                length = imageData.bytes.size.toULong()
            )
        }

        // Create UIImage from data
        val image = UIImage.imageWithData(nsData) ?: return imageData.bytes

        // Compress with iterative quality reduction
        return compressImageToTarget(image, ImageConfig.MAX_IMAGE_SIZE_BYTES.toLong())
    }

    /**
     * Compress a UIImage to target size
     */
    private fun compressImageToTarget(image: UIImage, targetSizeBytes: Long): ByteArray {
        var quality = ImageConfig.INITIAL_JPEG_QUALITY / 100.0
        var compressedData: NSData? = null

        while (quality >= ImageConfig.MIN_JPEG_QUALITY / 100.0) {
            compressedData = UIImageJPEGRepresentation(image, quality)

            if (compressedData != null && compressedData.length.toLong() <= targetSizeBytes) {
                break
            }

            quality -= 0.05 // Reduce quality by 5%
        }

        // Convert NSData to ByteArray
        return compressedData?.toByteArray() ?: image.let {
            UIImageJPEGRepresentation(it, ImageConfig.MIN_JPEG_QUALITY / 100.0)?.toByteArray() ?: ByteArray(0)
        }
    }

    /**
     * Convert NSData to ByteArray
     */
    private fun NSData.toByteArray(): ByteArray {
        return ByteArray(this.length.toInt()).apply {
            usePinned {
                memcpy(it.addressOf(0), this@toByteArray.bytes, this@toByteArray.length)
            }
        }
    }
}
