<?php


namespace api\classes;

use http\Exception\RuntimeException;

class imageProcessor
{
    public $postedFile = null;
    private $imageTmpPath;
    private $imageInfo;

    public $imageRestrictions = [
        'min_width' => 100,
        'max_width' => 600,
        'min_height' => 100,
        'max_height' => 600,
        'square' => false,
        'allowed_types' => ['image/png', 'image/jpeg', 'image/webp'],
        'max_size_kb' => 2048, // 2MB
        'transparent' => false
    ];

    private $finalImage = null;

    public function __construct($imageName)
    {
        if (isset($_FILES[$imageName]) && $_FILES[$imageName]['error'] === UPLOAD_ERR_OK) {
            $this->postedFile = $_FILES[$imageName];
            $this->imageTmpPath = $this->postedFile['tmp_name'];
            $this->imageInfo = getimagesize($this->imageTmpPath);
        } elseif (isset($_POST['image_base64'])) {
            $base64 = $_POST['image_base64'];

            if (preg_match('/^data:(image\/\w+);base64,/', $base64, $matches)) {
                $mimeType = $matches[1];
                $base64 = substr($base64, strpos($base64, ',') + 1);
            } else {
                throw new \RuntimeException('Invalid image data.');
            }

            $imageData = base64_decode($base64);
            if ($imageData === false) {
                throw new \RuntimeException('Invalid base64 image data.');
            }

            # Create image directly from string (no file)
            $srcImage = imagecreatefromstring($imageData);
            if (!$srcImage) {
                throw new \RuntimeException('Failed to create image from string.');
            }

            # Now you can get dimensions directly
            $width = imagesx($srcImage);
            $height = imagesy($srcImage);

            # Store $srcImage in a class property, continue processing in-memory
            $this->imageInfo = [
                'mime' => $mimeType,
                'width' => $width,
                'height' => $height,
                'size' => strlen($imageData)
            ];
        }
    }

    public function validateAndProcess()
    {
        if (!$this->postedFile) {
            return true;
        }
        $width = $this->imageInfo[0];
        $height = $this->imageInfo[1];
        $mime = $this->imageInfo['mime'];
        $fileSizeKB = filesize($this->imageTmpPath) / 1024;

        if (!in_array($mime, $this->imageRestrictions['allowed_types'])) {
            throw new \RuntimeException("Invalid image type: $mime");
        }

        if ($fileSizeKB > $this->imageRestrictions['max_size_kb']) {
            throw new \RuntimeException("Image exceeds max file size.");
        }

        # Resize to fit within min/max bounds
        $resizedImage = $this->resizeToFitRestrictions($mime, $width, $height);

        # Optionally square it
        if ($this->imageRestrictions['square']) {
            $resizedImage = $this->makeImageSquare($resizedImage, $mime);
        }

        ob_start();
        switch ($mime) {
            case 'image/jpeg':
                imagejpeg($resizedImage);
                break;
            case 'image/png':
                imagepng($resizedImage);
                break;
            case 'image/webp':
                imagewebp($resizedImage);
                break;
        }
        $this->finalImage = ob_get_clean();

        imagedestroy($resizedImage);

        return true;
    }

    private function mimeSupportsTransparency($mime)
    {
        return in_array($mime, ['image/png', 'image/webp']);
    }

    private function setTransparentCanvas($image, $width, $height): void
    {
        // Enable alpha blending and preserve alpha channel
        imagealphablending($image, false);
        imagesavealpha($image, true);

        // Fill the image with a fully transparent color
        $transparent = imagecolorallocatealpha($image, 0, 0, 0, 127);
        imagefilledrectangle($image, 0, 0, $width, $height, $transparent);

    }

    private function resizeToFitRestrictions($mime, $width, $height)
    {
        $minW = $this->imageRestrictions['min_width'];
        $maxW = $this->imageRestrictions['max_width'];
        $minH = $this->imageRestrictions['min_height'];
        $maxH = $this->imageRestrictions['max_height'];

        $srcImage = match ($mime) {
            'image/jpeg' => imagecreatefromjpeg($this->imageTmpPath),
            'image/png' => imagecreatefrompng($this->imageTmpPath),
            'image/webp' => imagecreatefromwebp($this->imageTmpPath),
            default => throw new \RuntimeException("Unsupported image type.")
        };

        # Determine new size
        $newWidth = $width;
        $newHeight = $height;

        if ($width < $minW || $width > $maxW || $height < $minH || $height > $maxH) {
            # Calculate scale factor based on limits
            $widthScale = ($width < $minW) ? $minW / $width : ($width > $maxW ? $maxW / $width : 1);
            $heightScale = ($height < $minH) ? $minH / $height : ($height > $maxH ? $maxH / $height : 1);

            # Use the smallest scale to ensure both dimensions fit
            $scale = min($widthScale, $heightScale);

            $newWidth = round($width * $scale);
            $newHeight = round($height * $scale);
        }

        $resizedImage = imagecreatetruecolor($newWidth, $newHeight);

        # keep transparent
        if ($this->mimeSupportsTransparency($mime)) {
            $this->setTransparentCanvas($resizedImage, $newWidth, $newHeight);
        }

        imagecopyresampled($resizedImage, $srcImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
        imagedestroy($srcImage);
        return $resizedImage;
    }

    private function makeImageSquare($srcImage, $mime)
    {
        $width = imagesx($srcImage);
        $height = imagesy($srcImage);

        $size = min($width, $height);
        $x = ($width - $size) / 2;
        $y = ($height - $size) / 2;

        $squareImage = imagecreatetruecolor($size, $size);

        # keep transparent
        if ($this->mimeSupportsTransparency($mime)) {
            $this->setTransparentCanvas($squareImage, $size, $size);
        }

        imagecopyresampled($squareImage, $srcImage, 0, 0, $x, $y, $size, $size, $size, $size);
        imagedestroy($srcImage);

        return $squareImage;
    }

    public function returnBase64image()
    {
        if ($this->finalImage) {
            return base64_encode($this->finalImage);
        } else {
            return false;
        }

    }
}