<?php

namespace AC\Helper;

use DOMDocument;
use DOMElement;

class Image extends Creatable
{

    public function resize(string $file, int $max_w, int $max_h, bool $crop = false): ?string
    {
        $editor = wp_get_image_editor($file);

        if (is_wp_error($editor)) {
            return null;
        }

        $editor->set_quality(90);

        $resized = $editor->resize($max_w, $max_h, $crop);

        if (is_wp_error($resized)) {
            return null;
        }

        $filename = $editor->generate_filename();
        $saved = $editor->save($filename);

        if (is_wp_error($saved)) {
            return null;
        }

        return $filename;
    }

    public function get_image_by_id(int $id, $size): ?string
    {
        if ( ! wp_get_attachment_url($id)) {
            return null;
        }

        $attributes = wp_get_attachment_image_src($id, $size);

        // Is Image
        if ($attributes) {
            [$src, $width, $height] = $attributes;

            if (
                is_array($size)
                && isset($size[0], $size[1])
                && is_numeric($size[0])
                && is_numeric($size[1])
                && $size[0] > 0
                && $size[1] > 0
            ) {
                return $this->markup_cover($src, (int)$size[0], (int)$size[1], $id);
            }

            // In case of SVG
            if (is_string($size) && 'svg' === pathinfo($src, PATHINFO_EXTENSION) && 'full' !== $size) {
                $_size = $this->get_image_sizes_by_name($size);

                $width = (int)($_size['width'] ?? 0);
                $height = (int)($_size['height'] ?? 0);
            }

            return $this->markup($src, $width, $height, $id);
        }

        $attributes = wp_get_attachment_image_src($id, $size, true);

        // Is File, use icon
        if ($attributes) {
            $width = (int)($attributes[1] ?? 0);
            $height = (int)($attributes[2] ?? 0);

            return $this->markup(
                $attributes[0],
                $this->scale_size($width, 0.8),
                $this->scale_size($height, 0.8),
                $id,
                true
            );
        }

        return null;
    }

    private function scale_size(int $size, float $scale = 1): int
    {
        return (int)round($size * $scale);
    }

    private function is_resized_image(string $path): bool
    {
        $fileinfo = pathinfo($path);

        return (bool)preg_match('/-[0-9]+x[0-9]+$/', $fileinfo['filename']);
    }

    private function get_dimensions_by_sizename($size): array
    {
        if (is_string($size)) {
            $sizes = $this->get_image_sizes_by_name($size);

            if ($sizes) {
                return [
                    (int)$sizes['width'],
                    (int)$sizes['height'],
                ];
            }
        }

        if (
            is_array($size)
            && isset($size[0], $size[1])
            && is_numeric($size[0])
            && is_numeric($size[1])
            && $size[0] > 0
            && $size[1] > 0
        ) {
            return [
                (int)$size[0],
                (int)$size[1],
            ];
        }

        return [60, 60];
    }

    public function get_image_by_url(string $url, $size): string
    {
        $dimensions = $this->get_dimensions_by_sizename($size);

        $width = $dimensions[0] ?? 0;
        $height = $dimensions[1] ?? 0;

        $image_path = (string)str_replace(WP_CONTENT_URL, WP_CONTENT_DIR, $url);

        if (is_file($image_path)) {
            // try to resize image if it is not already resized
            if ( ! $this->is_resized_image($image_path)) {
                $resized = $this->resize(
                    $image_path,
                    $width,
                    $height,
                    true
                );

                if ($resized) {
                    $src = str_replace(WP_CONTENT_DIR, WP_CONTENT_URL, $resized);

                    return $this->markup($src, $width, $height);
                }
            }

            return $this->markup($url, $width, $height);
        }

        // External image
        return $this->markup_cover($image_path, $width, $height);
    }

    public function get_image(string $image_id_or_url, $size = 'thumbnail'): ?string
    {
        if ( ! $image_id_or_url) {
            return null;
        }

        if (is_numeric($image_id_or_url)) {
            return $this->get_image_by_id((int)$image_id_or_url, $size);
        }

        if (Strings::create()->is_image($image_id_or_url)) {
            return $this->get_image_by_url($image_id_or_url, $size);
        }

        return null;
    }

    private function get_image_sizes_by_name(string $name): array
    {
        $available_sizes = wp_get_additional_image_sizes();

        foreach (['thumbnail', 'medium', 'large'] as $key) {
            $available_sizes[$key] = [
                'width'  => (int)get_option($key . '_size_w'),
                'height' => (int)get_option($key . '_size_h'),
            ];
        }

        return $available_sizes[$name] ?? [];
    }

    public function get_file_name(int $attachment_id): ?string
    {
        $file = get_post_meta($attachment_id, '_wp_attached_file', true);

        if ( ! $file) {
            return null;
        }

        return basename($file);
    }

    public function get_file_extension(int $attachment_id): string
    {
        return (string)pathinfo($this->get_file_name($attachment_id), PATHINFO_EXTENSION);
    }

    private function get_file_tooltip_attr(int $media_id): string
    {
        return Html::create()->get_tooltip_attr($this->get_file_name($media_id));
    }

    private function markup_cover(string $src, int $width, int $height, ?int $media_id = null)
    {
        ob_start(); ?>

		<span class="ac-image -cover" data-media-id="<?= esc_attr((string)$media_id); ?>">
			<img style="width:<?= esc_attr((string)$width); ?>px;height:<?= esc_attr((string)$height); ?>px;" src="<?= esc_attr(
                $src
            ); ?>" alt="">
		</span>

        <?php
        return ob_get_clean();
    }

    private function markup(string $src, int $width, int $height, ?int $media_id = null, ?bool $add_extension = false)
    {
        $class = '';

        if ($media_id && ! wp_attachment_is_image($media_id)) {
            $class = ' ac-icon';
        }

        $image_attributes = [
            'max-width'  => esc_attr((string)$width) . 'px',
            'max-height' => esc_attr((string)$height) . 'px',
        ];

        if (pathinfo($src, PATHINFO_EXTENSION) === 'svg') {
            $image_attributes['width'] = esc_attr((string)$width) . 'px';
            $image_attributes['height'] = esc_attr((string)$height) . 'px';
        }

        $tooltip_attr = $media_id
            ? $this->get_file_tooltip_attr($media_id)
            : '';

        ob_start(); ?>
		<span class="ac-image<?= $class ?>" data-media-id="<?= esc_attr((string)$media_id); ?>" <?= $tooltip_attr ?>>
			<img style="<?= Html::create()->get_style_attributes_as_string($image_attributes) ?>"
					src="<?= esc_attr($src) ?>" alt="">

			<?php
            if ($add_extension) : ?>
				<span class="ac-extension"><?= esc_attr($this->get_file_extension($media_id)) ?></span>
            <?php
            endif; ?>

		</span>

        <?php
        return ob_get_clean();
    }

    public function get_local_image_info(string $url): ?array
    {
        $path = $this->get_local_image_path($url);

        if ( ! $path) {
            return null;
        }

        return getimagesize($path);
    }

    public function get_local_image_path(string $url): ?string
    {
        $path = str_replace(WP_CONTENT_URL, WP_CONTENT_DIR, $url);

        if ( ! file_exists($path)) {
            return null;
        }

        return $path;
    }

    public function get_local_image_size(string $url): ?int
    {
        $path = $this->get_local_image_path($url);

        return $path
            ? filesize($path)
            : null;
    }

    public function get_image_urls_from_string(string $string): array
    {
        if ( ! $string) {
            return [];
        }

        if (false === strpos($string, '<img')) {
            return [];
        }

        if ( ! class_exists('DOMDocument')) {
            return [];
        }

        $dom = new DOMDocument();

        libxml_use_internal_errors(true);
        $dom->loadHTML($string);
        $dom->preserveWhiteSpace = false;
        libxml_clear_errors();

        $urls = [];

        $images = $dom->getElementsByTagName('img');

        foreach ($images as $img) {
            /** @var DOMElement $img */
            $src = $img->getAttribute('src');

            if ( ! $src) {
                continue;
            }

            $urls[] = $src;
        }

        return $urls;
    }

}