<?php

namespace Calio\Extensions;

use Elementor\Controls_Manager;

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

/**
 * Adds lightweight reveal and parallax motion controls to Elementor elements.
 */
class RevealParallaxExtension
{
    public function __construct()
    {
        add_action('elementor/element/common/section_effects/after_section_end', [$this, 'register_controls']);
        add_action('elementor/element/section/section_effects/after_section_end', [$this, 'register_controls']);
        add_action('elementor/element/column/section_effects/after_section_end', [$this, 'register_controls']);
        add_action('elementor/element/container/section_effects/after_section_end', [$this, 'register_controls']);

        add_action('elementor/frontend/widget/before_render', [$this, 'before_render']);
        add_action('elementor/frontend/section/before_render', [$this, 'before_render']);
        add_action('elementor/frontend/column/before_render', [$this, 'before_render']);
        add_action('elementor/frontend/container/before_render', [$this, 'before_render']);
    }

    /**
     * Registers reveal and parallax controls in the Advanced tab.
     *
     * @param object $element Elementor element instance.
     */
    public function register_controls($element): void
    {
        $element->start_controls_section(
            'calio_reveal_parallax',
            [
                'label' => esc_html__('Calio Reveal / Parallax', 'calio-addon'),
                'tab' => Controls_Manager::TAB_ADVANCED,
            ]
        );

        $element->add_control(
            'calio_reveal_enable',
            [
                'label' => esc_html__('Enable Reveal Motion', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => '',
            ]
        );

        $element->add_control(
            'calio_reveal_preset',
            [
                'label' => esc_html__('Reveal Preset', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'fade-up',
                'options' => [
                    'fade-up' => esc_html__('Fade Up', 'calio-addon'),
                    'fade-left' => esc_html__('Fade Left', 'calio-addon'),
                    'fade-right' => esc_html__('Fade Right', 'calio-addon'),
                    'zoom-in' => esc_html__('Zoom In', 'calio-addon'),
                    'soft-blur' => esc_html__('Soft Blur', 'calio-addon'),
                ],
                'condition' => ['calio_reveal_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_reveal_duration',
            [
                'label' => esc_html__('Duration', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => ['ms'],
                'default' => ['unit' => 'ms', 'size' => 700],
                'range' => ['ms' => ['min' => 200, 'max' => 1800, 'step' => 50]],
                'condition' => ['calio_reveal_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_reveal_delay',
            [
                'label' => esc_html__('Delay', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => ['ms'],
                'default' => ['unit' => 'ms', 'size' => 0],
                'range' => ['ms' => ['min' => 0, 'max' => 1200, 'step' => 50]],
                'condition' => ['calio_reveal_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_reveal_distance',
            [
                'label' => esc_html__('Distance', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => ['px'],
                'default' => ['unit' => 'px', 'size' => 28],
                'range' => ['px' => ['min' => 0, 'max' => 120, 'step' => 2]],
                'condition' => ['calio_reveal_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_reveal_viewport_threshold',
            [
                'label' => esc_html__('Viewport Threshold', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => ['%'],
                'default' => ['unit' => '%', 'size' => 18],
                'range' => ['%' => ['min' => 0, 'max' => 80, 'step' => 1]],
                'condition' => ['calio_reveal_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_reveal_easing_skin',
            [
                'label' => esc_html__('Easing Skin', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'balanced',
                'options' => [
                    'balanced' => esc_html__('Balanced', 'calio-addon'),
                    'snappy' => esc_html__('Snappy', 'calio-addon'),
                    'cinematic' => esc_html__('Cinematic', 'calio-addon'),
                ],
                'condition' => ['calio_reveal_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_reveal_once',
            [
                'label' => esc_html__('Reveal Once', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => 'yes',
                'condition' => ['calio_reveal_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_enable',
            [
                'label' => esc_html__('Enable Parallax Drift', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => '',
            ]
        );

        $element->add_control(
            'calio_parallax_type',
            [
                'label' => esc_html__('Parallax Type', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'scroll',
                'options' => [
                    'scroll' => esc_html__('Scroll', 'calio-addon'),
                    'scroll-zoom' => esc_html__('Scroll & Zoom', 'calio-addon'),
                    'fade' => esc_html__('Fade', 'calio-addon'),
                    'in-motion' => esc_html__('In Motion', 'calio-addon'),
                ],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_target',
            [
                'label' => esc_html__('Parallax Target', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'element',
                'options' => [
                    'element' => esc_html__('Element', 'calio-addon'),
                    'background' => esc_html__('Background Image', 'calio-addon'),
                ],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_orientation',
            [
                'label' => esc_html__('Orientation', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'up',
                'options' => [
                    'up' => esc_html__('Up', 'calio-addon'),
                    'down' => esc_html__('Down', 'calio-addon'),
                    'left' => esc_html__('Left', 'calio-addon'),
                    'right' => esc_html__('Right', 'calio-addon'),
                    'up-left' => esc_html__('Up Left', 'calio-addon'),
                    'up-right' => esc_html__('Up Right', 'calio-addon'),
                    'down-left' => esc_html__('Down Left', 'calio-addon'),
                    'down-right' => esc_html__('Down Right', 'calio-addon'),
                ],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_axis',
            [
                'label' => esc_html__('Moving Direction', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'y',
                'options' => [
                    'y' => esc_html__('Vertical', 'calio-addon'),
                    'x' => esc_html__('Horizontal', 'calio-addon'),
                    'y-reverse' => esc_html__('Vertical Reverse', 'calio-addon'),
                    'x-reverse' => esc_html__('Horizontal Reverse', 'calio-addon'),
                ],
                'condition' => [
                    'calio_parallax_enable' => 'yes',
                    'calio_parallax_type' => 'in-motion',
                ],
            ]
        );

        $element->add_control(
            'calio_parallax_speed',
            [
                'label' => esc_html__('Movement Amount', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [''],
                'default' => ['unit' => '', 'size' => 140],
                'range' => ['' => ['min' => 0, 'max' => 420, 'step' => 5]],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_scale',
            [
                'label' => esc_html__('Parallax Scale', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [''],
                'default' => ['unit' => '', 'size' => 112],
                'range' => ['' => ['min' => 100, 'max' => 160, 'step' => 1]],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_delay',
            [
                'label' => esc_html__('Smooth Delay', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [''],
                'default' => ['unit' => '', 'size' => 18],
                'range' => ['' => ['min' => 0, 'max' => 60, 'step' => 1]],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_android',
            [
                'label' => esc_html__('Enable On Android', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => '',
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_ios',
            [
                'label' => esc_html__('Enable On iOS', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => '',
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_tablet',
            [
                'label' => esc_html__('Enable On Tablet', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => '',
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_desktop',
            [
                'label' => esc_html__('Enable On Desktop', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => 'yes',
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_viewport',
            [
                'label' => esc_html__('Viewport Range', 'calio-addon'),
                'type' => Controls_Manager::SLIDER,
                'size_units' => ['%'],
                'default' => ['unit' => '%', 'size' => 100],
                'range' => ['%' => ['min' => 40, 'max' => 160, 'step' => 5]],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_depth',
            [
                'label' => esc_html__('Depth', 'calio-addon'),
                'type' => Controls_Manager::SELECT,
                'default' => 'balanced',
                'options' => [
                    'subtle' => esc_html__('Subtle', 'calio-addon'),
                    'balanced' => esc_html__('Balanced', 'calio-addon'),
                    'strong' => esc_html__('Strong', 'calio-addon'),
                ],
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->add_control(
            'calio_parallax_overflow_hidden',
            [
                'label' => esc_html__('Clip Overflow', 'calio-addon'),
                'type' => Controls_Manager::SWITCHER,
                'return_value' => 'yes',
                'default' => '',
                'condition' => ['calio_parallax_enable' => 'yes'],
            ]
        );

        $element->end_controls_section();
    }

    /**
     * Adds render attributes for frontend reveal/parallax runtime.
     *
     * @param object $element Elementor element instance.
     */
    public function before_render($element): void
    {
        $settings = $element->get_settings_for_display();
        $reveal_enabled = ($settings['calio_reveal_enable'] ?? '') === 'yes';
        $parallax_enabled = ($settings['calio_parallax_enable'] ?? '') === 'yes';

        if (!$reveal_enabled && !$parallax_enabled) {
            return;
        }

        $duration = isset($settings['calio_reveal_duration']['size']) ? (int) $settings['calio_reveal_duration']['size'] : 700;
        $delay = isset($settings['calio_reveal_delay']['size']) ? (int) $settings['calio_reveal_delay']['size'] : 0;
        $distance = isset($settings['calio_reveal_distance']['size']) ? (int) $settings['calio_reveal_distance']['size'] : 28;
        $threshold = isset($settings['calio_reveal_viewport_threshold']['size']) ? (float) $settings['calio_reveal_viewport_threshold']['size'] : 18.0;
        $speed = isset($settings['calio_parallax_speed']['size']) ? (float) $settings['calio_parallax_speed']['size'] : 140.0;
        $scale = isset($settings['calio_parallax_scale']['size']) ? (float) $settings['calio_parallax_scale']['size'] : 112.0;
        $parallax_delay = isset($settings['calio_parallax_delay']['size']) ? (float) $settings['calio_parallax_delay']['size'] : 18.0;
        $reveal_preset = $this->allowlisted_value((string) ($settings['calio_reveal_preset'] ?? 'fade-up'), ['fade-up', 'fade-left', 'fade-right', 'zoom-in', 'soft-blur'], 'fade-up');
        $easing_skin = $this->allowlisted_value((string) ($settings['calio_reveal_easing_skin'] ?? 'balanced'), ['balanced', 'snappy', 'cinematic'], 'balanced');
        $parallax_type = $this->allowlisted_value((string) ($settings['calio_parallax_type'] ?? 'scroll'), ['scroll', 'scroll-zoom', 'fade', 'in-motion'], 'scroll');
        $parallax_target = $this->allowlisted_value((string) ($settings['calio_parallax_target'] ?? 'element'), ['element', 'background'], 'element');
        $parallax_orientation = $this->allowlisted_value((string) ($settings['calio_parallax_orientation'] ?? 'up'), ['up', 'down', 'left', 'right', 'up-left', 'up-right', 'down-left', 'down-right'], 'up');
        $parallax_axis = $this->allowlisted_value((string) ($settings['calio_parallax_axis'] ?? 'y'), ['y', 'x', 'y-reverse', 'x-reverse'], 'y');
        $parallax_depth = $this->allowlisted_value((string) ($settings['calio_parallax_depth'] ?? 'balanced'), ['subtle', 'balanced', 'strong'], 'balanced');

        $element->add_render_attribute(
            '_wrapper',
            [
                'data-calio-reveal-parallax' => 'yes',
                'data-calio-reveal-enabled' => $reveal_enabled ? 'yes' : 'no',
                'data-calio-reveal-preset' => $reveal_preset,
                'data-calio-reveal-duration' => (string) max(200, min(1800, $duration)),
                'data-calio-reveal-delay' => (string) max(0, min(1200, $delay)),
                'data-calio-reveal-distance' => (string) max(0, min(120, $distance)),
                'data-calio-reveal-threshold' => (string) max(0, min(80, $threshold)),
                'data-calio-reveal-easing-skin' => $easing_skin,
                'data-calio-reveal-once' => (($settings['calio_reveal_once'] ?? 'yes') === 'yes') ? 'yes' : 'no',
                'data-calio-parallax-enabled' => $parallax_enabled ? 'yes' : 'no',
                'data-calio-parallax-type' => $parallax_type,
                'data-calio-parallax-target' => $parallax_target,
                'data-calio-parallax-orientation' => $parallax_orientation,
                'data-calio-parallax-axis' => $parallax_axis,
                'data-calio-parallax-speed' => (string) max(0, min(420, $speed)),
                'data-calio-parallax-scale' => (string) max(100, min(160, $scale)),
                'data-calio-parallax-delay' => (string) max(0, min(60, $parallax_delay)),
                'data-calio-parallax-android' => (($settings['calio_parallax_android'] ?? '') === 'yes') ? 'yes' : 'no',
                'data-calio-parallax-ios' => (($settings['calio_parallax_ios'] ?? '') === 'yes') ? 'yes' : 'no',
                'data-calio-parallax-tablet' => (($settings['calio_parallax_tablet'] ?? '') === 'yes') ? 'yes' : 'no',
                'data-calio-parallax-desktop' => (($settings['calio_parallax_desktop'] ?? 'yes') === 'yes') ? 'yes' : 'no',
                'data-calio-parallax-viewport' => isset($settings['calio_parallax_viewport']['size']) ? (string) max(40, min(160, (float) $settings['calio_parallax_viewport']['size'])) : '100',
                'data-calio-parallax-depth' => $parallax_depth,
                'data-calio-parallax-overflow' => (($settings['calio_parallax_overflow_hidden'] ?? '') === 'yes') ? 'hidden' : 'visible',
            ]
        );
    }

    /**
     * Keeps data attributes aligned with declared Elementor select options.
     *
     * @param string   $value    Submitted control value.
     * @param string[] $allowed  Allowed values.
     * @param string   $fallback Fallback value.
     */
    private function allowlisted_value(string $value, array $allowed, string $fallback): string
    {
        $value = sanitize_key($value);

        return in_array($value, $allowed, true) ? $value : $fallback;
    }
}
