<?php

declare(strict_types=1);

namespace Intervention\Image\Drivers\Gd\Modifiers;

use Intervention\Image\Exceptions\AnimationException;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Geometry\Point;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SpecializedInterface;
use Intervention\Image\Modifiers\TrimModifier as GenericTrimModifier;

class TrimModifier extends GenericTrimModifier implements SpecializedInterface
{
    /**
     * {@inheritdoc}
     *
     * @see ModifierInterface::apply()
     */
    public function apply(ImageInterface $image): ImageInterface
    {
        if ($image->isAnimated()) {
            throw new NotSupportedException('Trim modifier cannot be applied to animated images.');
        }

        // apply tolerance with a min. value of .5 because the default tolerance of '0' should
        // already trim away similar colors which is not the case with imagecropauto.
        $trimmed = imagecropauto(
            $image->core()->native(),
            IMG_CROP_THRESHOLD,
            max([.5, $this->tolerance / 10]),
            $this->trimColor($image)
        );

        // if the tolerance is very high, it is possible that no image is left.
        // imagick returns a 1x1 pixel image in this case. this does the same.
        if ($trimmed === false) {
            $trimmed = $this->driver()->createImage(1, 1)->core()->native();
        }

        $image->core()->setNative($trimmed);

        return $image;
    }

    /**
     * Create an average color from the colors of the four corner points of the given image
     *
     * @param ImageInterface $image
     * @throws RuntimeException
     * @throws AnimationException
     * @return int
     */
    private function trimColor(ImageInterface $image): int
    {
        // trim color base
        $red = 0;
        $green = 0;
        $blue = 0;

        // corner coordinates
        $size = $image->size();
        $cornerPoints = [
            new Point(0, 0),
            new Point($size->width() - 1, 0),
            new Point(0, $size->height() - 1),
            new Point($size->width() - 1, $size->height() - 1),
        ];

        // create an average color to be used in trim operation
        foreach ($cornerPoints as $pos) {
            $cornerColor = imagecolorat($image->core()->native(), $pos->x(), $pos->y());
            $rgb = imagecolorsforindex($image->core()->native(), $cornerColor);
            $red += round(round(($rgb['red'] / 51)) * 51);
            $green += round(round(($rgb['green'] / 51)) * 51);
            $blue += round(round(($rgb['blue'] / 51)) * 51);
        }

        $red = (int) round($red / 4);
        $green = (int) round($green / 4);
        $blue = (int) round($blue / 4);

        return imagecolorallocate($image->core()->native(), $red, $green, $blue);
    }
}
