<?php

namespace Calio\Extensions;

use Elementor\Controls_Manager;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Adds Calio-prefixed backdrop and liquid glass filter controls to Elementor wrappers.
 */
class GlassFilterExtension
{
    private static bool $svg_printed = false;
    /**
     * @var array<string, bool>
     */
    private static array $printed_svg_ids = [];

    public function __construct()
    {
        add_action('elementor/element/column/section_style/before_section_end', [$this, 'register_controls'], 10, 2);
        add_action('elementor/element/common/_section_background/before_section_end', [$this, 'register_controls'], 10, 2);
        add_action('elementor/element/container/section_background/before_section_end', [$this, 'register_controls'], 10, 2);
        add_action('elementor/element/section/section_background/before_section_end', [$this, 'register_controls'], 10, 2);

        add_action('elementor/frontend/before_render', [$this, 'before_render']);
        add_action('wp_footer', [$this, 'print_preview_svg']);
    }

    /**
     * Registers the Glass Filter controls in Elementor background/style panels.
     *
     * @param object $element Elementor element instance.
     */
    public function register_controls($element): void
    {
        $element->add_control(
            'calio_glass_filter',
            [
                'label' => esc_html__('Glass Filter', 'calio-addon'),
                'type' => Controls_Manager::POPOVER_TOGGLE,
                'return_value' => 'yes',
                'prefix_class' => 'calio-glass-filter-',
                'render_type' => 'template',
            ]
        );

        $element->start_popover();

        $element->add_control(
            'calio_glass_filter_type',
            [
                'label' => esc_html__('Filter Type', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'backdrop',
                'options' => [
                    'backdrop' => esc_html__('Backdrop Blur', 'calio-addon'),
                    'liquid_glass' => esc_html__('Liquid Glass', 'calio-addon'),
                ],
                'prefix_class' => 'calio-glass-type-',
                'render_type' => 'template',
                'condition' => [
                    'calio_glass_filter' => 'yes',
                ],
            ]
        );

        $element->add_control(
            'calio_glass_filter_notice',
            [
                'type' => Controls_Manager::RAW_HTML,
                'raw' => '<div class="elementor-panel-alert elementor-panel-alert-info">' . esc_html__('Backdrop filter support depends on the browser.', 'calio-addon') . '</div>',
                'content_classes' => 'calio-control-alert',
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => 'backdrop',
                ],
            ]
        );

        $this->add_filter_slider($element, 'calio_glass_filter_blur', esc_html__('Blur', 'calio-addon'), '--calio-glass-filter-blur', 'px', 8, 0, 60, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_brightness', esc_html__('Brightness', 'calio-addon'), '--calio-glass-filter-brightness', '%', 105, 0, 250, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_contrast', esc_html__('Contrast', 'calio-addon'), '--calio-glass-filter-contrast', '%', 100, 0, 250, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_grayscale', esc_html__('Grayscale', 'calio-addon'), '--calio-glass-filter-grayscale', '%', 0, 0, 100, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_invert', esc_html__('Invert', 'calio-addon'), '--calio-glass-filter-invert', '%', 0, 0, 100, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_opacity', esc_html__('Opacity', 'calio-addon'), '--calio-glass-filter-opacity', '%', 100, 0, 100, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_sepia', esc_html__('Sepia', 'calio-addon'), '--calio-glass-filter-sepia', '%', 0, 0, 100, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_saturate', esc_html__('Saturate', 'calio-addon'), '--calio-glass-filter-saturate', '%', 120, 0, 300, 1, 'backdrop');
        $this->add_filter_slider($element, 'calio_glass_filter_hue_rotate', esc_html__('Hue Rotate', 'calio-addon'), '--calio-glass-filter-hue-rotate', 'deg', 0, -180, 180, 1, 'backdrop');

        $element->add_control(
            'calio_liquid_glass_blur',
            [
                'label' => esc_html__('Liquid Blur', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => ['px'],
                'default' => [
                    'unit' => 'px',
                    'size' => 1,
                ],
                'range' => [
                    'px' => [
                        'min' => 0,
                        'max' => 20,
                        'step' => 0.1,
                    ],
                ],
                'selectors' => [
                    '{{WRAPPER}}' => '--calio-liquid-glass-blur: {{SIZE}}{{UNIT}};',
                ],
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => 'liquid_glass',
                ],
            ]
        );

        $element->add_control(
            'calio_liquid_glass_surface_color',
            [
                'label' => esc_html__('Surface Tint', 'calio-addon'),
                'type' => Controls_Manager::COLOR,
                'default' => 'rgba(255,255,255,0.22)',
                'selectors' => [
                    '{{WRAPPER}}' => '--calio-liquid-glass-surface-color: {{VALUE}};',
                ],
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => 'liquid_glass',
                ],
            ]
        );

        $this->add_liquid_css_slider($element, 'calio_liquid_glass_surface_opacity', esc_html__('Surface Opacity', 'calio-addon'), '--calio-liquid-glass-surface-opacity', '', 1, 0, 1, 0.01);
        $this->add_liquid_css_slider($element, 'calio_liquid_glass_highlight_opacity', esc_html__('Highlight Opacity', 'calio-addon'), '--calio-liquid-glass-highlight-opacity', '', 0.42, 0, 1, 0.01);
        $this->add_liquid_css_slider($element, 'calio_liquid_glass_saturate', esc_html__('Backdrop Saturate', 'calio-addon'), '--calio-liquid-glass-saturate', '%', 150, 0, 300, 1);
        $this->add_liquid_css_slider($element, 'calio_liquid_glass_edge_bleed', esc_html__('Edge Bleed', 'calio-addon'), '--calio-liquid-glass-edge-bleed', 'px', 18, 0, 60, 1);
        $this->add_liquid_css_slider($element, 'calio_liquid_glass_edge_opacity', esc_html__('Edge Fill', 'calio-addon'), '--calio-liquid-glass-edge-opacity', '', 0.55, 0, 8, 0.05);

        $element->add_control(
            'calio_liquid_glass_border_color',
            [
                'label' => esc_html__('Border Color', 'calio-addon'),
                'type' => Controls_Manager::COLOR,
                'default' => 'rgba(255,255,255,0.34)',
                'selectors' => [
                    '{{WRAPPER}}' => '--calio-liquid-glass-border-color: {{VALUE}};',
                ],
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => 'liquid_glass',
                ],
            ]
        );

        $this->add_liquid_css_slider($element, 'calio_liquid_glass_border_width', esc_html__('Border Width', 'calio-addon'), '--calio-liquid-glass-border-width', 'px', 1, 0, 8, 1);

        $element->add_control(
            'calio_liquid_glass_notice',
            [
                'type' => Controls_Manager::RAW_HTML,
                'raw' => esc_html__('Liquid glass works best on semi-transparent surfaces with an image or colorful layer behind the element.', 'calio-addon'),
                'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => 'liquid_glass',
                ],
            ]
        );

        $this->add_liquid_slider($element, 'calio_liquid_glass_distortion', esc_html__('Distortion Strength', 'calio-addon'), 150, 0, 300, 1);
        $this->add_liquid_slider($element, 'calio_liquid_glass_noise_frequency', esc_html__('Noise Frequency', 'calio-addon'), 0.01, 0.001, 0.08, 0.001);
        $this->add_liquid_slider($element, 'calio_liquid_glass_detail', esc_html__('Noise Detail', 'calio-addon'), 1, 1, 4, 1);
        $this->add_liquid_slider($element, 'calio_liquid_glass_seed', esc_html__('Noise Seed', 'calio-addon'), 5, 1, 40, 1);
        $this->add_liquid_slider($element, 'calio_liquid_glass_softness', esc_html__('Map Softness', 'calio-addon'), 3, 0, 12, 0.1);
        $this->add_liquid_slider($element, 'calio_liquid_glass_surface_scale', esc_html__('Surface Scale', 'calio-addon'), 5, 0, 16, 0.1);
        $this->add_liquid_slider($element, 'calio_liquid_glass_highlight', esc_html__('Highlight Strength', 'calio-addon'), 1, 0, 4, 0.05);
        $this->add_liquid_slider($element, 'calio_liquid_glass_highlight_sharpness', esc_html__('Highlight Sharpness', 'calio-addon'), 100, 1, 240, 1);
        $this->add_liquid_slider($element, 'calio_liquid_glass_light_x', esc_html__('Light X', 'calio-addon'), -200, -500, 500, 5);
        $this->add_liquid_slider($element, 'calio_liquid_glass_light_y', esc_html__('Light Y', 'calio-addon'), -200, -500, 500, 5);
        $this->add_liquid_slider($element, 'calio_liquid_glass_light_z', esc_html__('Light Z', 'calio-addon'), 300, 0, 800, 5);

        $element->end_popover();
    }

    /**
     * Adds frontend classes and prints the SVG filter when liquid glass is active.
     *
     * @param object $element Elementor element instance.
     */
    public function before_render($element): void
    {
        $settings = $element->get_settings_for_display();

        if (($settings['calio_glass_filter'] ?? '') !== 'yes') {
            return;
        }

        $type = ($settings['calio_glass_filter_type'] ?? 'backdrop') === 'liquid_glass' ? 'liquid' : 'backdrop';

        $attributes = [
            'class' => [
                'calio-glass-filter-enabled',
                'calio-glass-filter-' . $type,
            ],
            'data-calio-glass-filter' => $type,
        ];

        if ($type === 'liquid') {
            $filter_id = 'calio-glass-frosted-' . sanitize_html_class((string) $element->get_id());
            $attributes['style'] = '--calio-liquid-glass-filter-url: url(#' . esc_attr($filter_id) . ');';
        }

        $element->add_render_attribute(
            '_wrapper',
            $attributes
        );

        if ($type === 'liquid') {
            $this->print_svg($filter_id, $settings);
        }
    }

    public function print_preview_svg(): void
    {
        if (!$this->is_elementor_context()) {
            return;
        }

        $this->print_svg('calio-glass-frosted');
    }

    private function add_filter_slider($element, string $name, string $label, string $css_variable, string $unit, float $default, float $min, float $max, float $step, string $type): void
    {
        $element->add_control(
            $name,
            [
                'label' => $label,
                'type' => Controls_Manager::SLIDER,
                'size_units' => [$unit],
                'default' => [
                    'unit' => $unit,
                    'size' => $default,
                ],
                'range' => [
                    $unit => [
                        'min' => $min,
                        'max' => $max,
                        'step' => $step,
                    ],
                ],
                'selectors' => [
                    '{{WRAPPER}}' => $css_variable . ': {{SIZE}}{{UNIT}};',
                ],
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => $type,
                ],
            ]
        );
    }

    private function add_liquid_slider($element, string $name, string $label, float $default, float $min, float $max, float $step): void
    {
        $element->add_control(
            $name,
            [
                'label' => $label,
                'type' => Controls_Manager::SLIDER,
                'size_units' => [''],
                'default' => [
                    'unit' => '',
                    'size' => $default,
                ],
                'range' => [
                    '' => [
                        'min' => $min,
                        'max' => $max,
                        'step' => $step,
                    ],
                ],
                'render_type' => 'template',
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => 'liquid_glass',
                ],
            ]
        );
    }

    private function add_liquid_css_slider($element, string $name, string $label, string $css_variable, string $unit, float $default, float $min, float $max, float $step): void
    {
        $element->add_control(
            $name,
            [
                'label' => $label,
                'type' => Controls_Manager::SLIDER,
                'size_units' => [$unit],
                'default' => [
                    'unit' => $unit,
                    'size' => $default,
                ],
                'range' => [
                    $unit => [
                        'min' => $min,
                        'max' => $max,
                        'step' => $step,
                    ],
                ],
                'selectors' => [
                    '{{WRAPPER}}' => $css_variable . ': {{SIZE}}{{UNIT}};',
                ],
                'condition' => [
                    'calio_glass_filter' => 'yes',
                    'calio_glass_filter_type' => 'liquid_glass',
                ],
            ]
        );
    }

    /**
     * @param array<string, mixed> $settings
     */
    private function print_svg(string $id = 'calio-glass-frosted', array $settings = []): void
    {
        $id = sanitize_html_class($id);
        if ($id === '') {
            $id = 'calio-glass-frosted';
        }

        if (!empty(self::$printed_svg_ids[$id])) {
            return;
        }

        self::$printed_svg_ids[$id] = true;
        self::$svg_printed = true;

        $frequency = $this->slider_value($settings, 'calio_liquid_glass_noise_frequency', 0.01, 0.001, 0.08);
        $octaves = (int) round($this->slider_value($settings, 'calio_liquid_glass_detail', 1, 1, 4));
        $seed = (int) round($this->slider_value($settings, 'calio_liquid_glass_seed', 5, 1, 40));
        $softness = $this->slider_value($settings, 'calio_liquid_glass_softness', 3, 0, 12);
        $surface_scale = $this->slider_value($settings, 'calio_liquid_glass_surface_scale', 5, 0, 16);
        $highlight = $this->slider_value($settings, 'calio_liquid_glass_highlight', 1, 0, 4);
        $sharpness = $this->slider_value($settings, 'calio_liquid_glass_highlight_sharpness', 100, 1, 240);
        $light_x = $this->slider_value($settings, 'calio_liquid_glass_light_x', -200, -500, 500);
        $light_y = $this->slider_value($settings, 'calio_liquid_glass_light_y', -200, -500, 500);
        $light_z = $this->slider_value($settings, 'calio_liquid_glass_light_z', 300, 0, 800);
        $distortion = $this->slider_value($settings, 'calio_liquid_glass_distortion', 150, 0, 300);

        echo '<svg class="calio-glass-filter-svg" aria-hidden="true" focusable="false" style="display:none" width="0" height="0" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"><filter id="' . esc_attr($id) . '" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox"><feTurbulence type="fractalNoise" baseFrequency="' . esc_attr($this->format_number($frequency) . ' ' . $this->format_number($frequency)) . '" numOctaves="' . esc_attr((string) $octaves) . '" seed="' . esc_attr((string) $seed) . '" result="turbulence"/><feComponentTransfer in="turbulence" result="mapped"><feFuncR type="gamma" amplitude="1" exponent="10" offset="0.5"/><feFuncG type="gamma" amplitude="0" exponent="1" offset="0"/><feFuncB type="gamma" amplitude="0" exponent="1" offset="0.5"/></feComponentTransfer><feGaussianBlur in="turbulence" stdDeviation="' . esc_attr($this->format_number($softness)) . '" result="softMap"/><feSpecularLighting in="softMap" surfaceScale="' . esc_attr($this->format_number($surface_scale)) . '" specularConstant="' . esc_attr($this->format_number($highlight)) . '" specularExponent="' . esc_attr($this->format_number($sharpness)) . '" lighting-color="white" result="specLight"><fePointLight x="' . esc_attr($this->format_number($light_x)) . '" y="' . esc_attr($this->format_number($light_y)) . '" z="' . esc_attr($this->format_number($light_z)) . '"/></feSpecularLighting><feComposite in="specLight" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litImage"/><feDisplacementMap in="SourceGraphic" in2="softMap" scale="' . esc_attr($this->format_number($distortion)) . '" xChannelSelector="R" yChannelSelector="G"/></filter></svg>';
    }

    /**
     * @param array<string, mixed> $settings
     */
    private function slider_value(array $settings, string $key, float $default, float $min, float $max): float
    {
        $value = $default;
        if (isset($settings[$key]['size'])) {
            $value = (float) $settings[$key]['size'];
        } elseif (isset($settings[$key]) && is_numeric($settings[$key])) {
            $value = (float) $settings[$key];
        }

        return max($min, min($max, $value));
    }

    private function format_number(float $value): string
    {
        $formatted = rtrim(rtrim(number_format($value, 3, '.', ''), '0'), '.');
        return $formatted === '-0' ? '0' : $formatted;
    }

    private function is_elementor_context(): bool
    {
        // Read-only Elementor context detection.
        // phpcs:disable WordPress.Security.NonceVerification.Recommended
        if (isset($_GET['elementor-preview']) || isset($_GET['elementor-preview-iframe'])) {
            return true;
        }

        if (isset($_GET['action']) && sanitize_key((string) wp_unslash($_GET['action'])) === 'elementor') {
            return true;
        }
        // phpcs:enable WordPress.Security.NonceVerification.Recommended

        if (!class_exists('\\Elementor\\Plugin')) {
            return false;
        }

        $plugin = \Elementor\Plugin::$instance ?? null;
        if (!is_object($plugin)) {
            return false;
        }

        $is_preview = isset($plugin->preview) && method_exists($plugin->preview, 'is_preview_mode') && $plugin->preview->is_preview_mode();
        $is_editor = isset($plugin->editor) && method_exists($plugin->editor, 'is_edit_mode') && $plugin->editor->is_edit_mode();

        return $is_preview || $is_editor;
    }
}
