<?php

/**
 * Class ESSB_Runtime_CSS_Builder
 *
 * Responsible for building and managing runtime-generated CSS for the Easy Social Share Buttons plugin.
 *
 * @package    EasySocialShareButtons
 * @subpackage Assets
 * @author     EasySocialShareButtonsTeam
 * @since      10.5
 */
class ESSB_Runtime_CSS_Builder
{

    /**
     * Holds the dynamically generated CSS code.
     *
     * @var array
     */
    private static $dynamic_code = array();

    /**
     * Resets the runtime CSS builder to its initial state.
     *
     * This static method is typically used to clear any previously set CSS rules or configurations,
     * allowing the builder to start fresh. It is useful when you need to regenerate or discard
     * dynamic CSS during the plugin's execution.
     *
     * @return void
     */
    public static function reset()
    {
        self::$dynamic_code = array();
    }

    /**
     * Initializes the runtime CSS builder.
     *
     * @param string $key Optional. A unique key to identify the CSS builder instance. Default is an empty string.
     * @return void
     */
    public static function init($key = '')
    {
        self::$dynamic_code[$key] = array();
    }

    /**
     * Initializes the runtime CSS builder if the specified key is provided.
     *
     * This static method checks if a given key is set and performs initialization
     * tasks for the runtime CSS builder accordingly.
     *
     * @param string $key Optional. The key used to determine if initialization should occur. Default is an empty string.
     * @return void
     */
    public static function maybe_init($key = '')
    {
        if (!isset(self::$dynamic_code[$key])) {
            self::init($key);
        }
    }

    /**
     * Initializes a CSS selector if necessary.
     *
     * This method checks if a given CSS selector (identified by $key and $selector) 
     * needs to be initialized in the runtime CSS builder context. It may perform 
     * setup or registration tasks for the selector.
     *
     * @param string $key      Optional. A unique key identifying the selector. Default is an empty string.
     * @param string $selector Optional. The actual CSS selector string. Default is an empty string.
     * @return void
     */
    public static function maybe_init_selector($key = '', $selector = '')
    {
        if (isset(self::$dynamic_code[$key])) {
            if (!isset(self::$dynamic_code[$key][$selector])) {
                self::$dynamic_code[$key][$selector] = array();
            }
        }
    }

    /**
     * Registers a CSS rule for runtime generation.
     *
     * @param string  $key        Unique identifier for the CSS rule.
     * @param string  $selector   CSS selector to which the rule applies.
     * @param string  $prop       CSS property name.
     * @param string  $value      Value for the CSS property.
     * @param string  $suffix     Optional suffix to append to the value (e.g., 'px', '%').
     * @param bool    $important  Whether to add '!important' to the rule.
     * @param string  $min_width  Optional minimum width for media query (e.g., '768px').
     * @param string  $max_width  Optional maximum width for media query (e.g., '1200px').
     */
    public static function register($key = '', $selector = '', $prop = '', $value = '', $suffix = '', $important = false, $min_width = '', $max_width = '')
    {
        self::maybe_init($key);
        self::maybe_init_selector($key, $selector);

        self::$dynamic_code[$key][$selector][$prop] = array(
            'value' => $value,
            'suffix' => $suffix,
            'important' => $important,
            'min_width' => $min_width,
            'max_width' => $max_width
        );
    }

    public static function register_multiple($key = '', $selector = '', $properties = array(), $min_width = '', $max_width = '')
    {
        foreach ($properties as $prop => $details) {
            $temporary_value = $details;
            if (!is_array($details)) {
                $details = array();
                $details['value'] = $temporary_value;
            }

            if (!isset($details['value'])) {
                $details['value'] = '';
            }

            if (!isset($details['suffix'])) {
                $details['suffix'] = '';
            }

            if (!isset($details['important'])) {
                $details['important'] = '';
            }

            self::register($key, $selector, $prop, $details['value'], $details['suffix'], $details['important'], $min_width, $max_width);
        }
    }

    /**
     * Compiles the runtime CSS for a given key.
     *
     * @param string $key Optional. The identifier for the CSS block to compile. Default is an empty string.
     * @return mixed The compiled CSS or relevant result based on the implementation.
     */
    public static function compile($key = '')
    {
        $output = '';

        if (isset(self::$dynamic_code[$key])) {
            $selectors = self::$dynamic_code[$key];
            $split_by_device_selectors = self::split_by_devices($selectors);

            $output .= self::build_css($split_by_device_selectors['global']);

            // Begin generation of device selectors
            foreach ($split_by_device_selectors['devices'] as $key => $device_data) {
                $output .= '@media ';

                if (!empty($device_data['min_width']) && !empty($device_data['max_width'])) {
                    $output .= '(min-width: ' . esc_attr($device_data['min_width']) . 'px) and (max-width: ' . esc_attr($device_data['max_width']) . 'px)';
                } else if (!empty($device_data['min_width'])) {
                    $output .= '(min-width: ' . esc_attr($device_data['min_width']) . 'px)';
                } else if (!empty($device_data['max_width'])) {
                    $output .= '(max-width: ' . esc_attr($device_data['max_width']) . 'px)';
                }

                $output .= '{';

                $output .= self::build_css($device_data['selectors']);

                $output .= '}';
            }
        }

        return $output;
    }

    /**
     * Splits the provided CSS selectors by device type (e.g., desktop, tablet, mobile).
     *
     * @param array $selectors An array of CSS selectors to be split by device.
     * @return array An associative array containing selectors grouped by device type.
     */
    public static function split_by_devices($selectors = array())
    {
        $output = array('global' => array(), 'devices' => array());

        foreach ($selectors as $selector => $props) {
            foreach ($props as $prop => $data) {

                if ($data['value'] == '') {
                    continue;
                }

                // This code runs no matter of the device
                if (empty($data['min_width']) && empty($data['max_width'])) {
                    if (!isset($output['global'][$selector])) {
                        $output['global'][$selector] = array();
                    }
                    $output['global'][$selector][$prop] = $data;
                } else {
                    $device_key = 'width-' . $data['min_width'] . '-' . $data['max_width'];

                    if (!isset($output['devices'][$device_key])) {
                        $output['devices'][$device_key] = array('min_width' => $data['min_width'], 'max_width' => $data['max_width'], 'selectors' => array());
                    }

                    if (!isset($output['devices'][$device_key]['selectors'][$selector])) {
                        $output['devices'][$device_key]['selectors'][$selector] = array();
                    }

                    $output['devices'][$device_key]['selectors'][$selector][$prop] = $data;
                }
            }
        }

        return $output;
    }

    /**
     * Builds CSS rules from the provided selectors array.
     *
     * This static method generates CSS code based on the given selectors and their associated styles.
     *
     * @param array $selectors An associative array where keys are CSS selectors and values are arrays of CSS properties and values.
     * @return string The generated CSS code as a string.
     */
    public static function build_css($selectors = array())
    {
        $output = '';

        foreach ($selectors as $selector => $props) {
            $part = $selector . '{';

            $one_prop = false;
            foreach ($props as $prop => $data) {
                if ($data['value'] == '') {
                    continue;
                }

                $value = $data['value'];

                $part .= esc_attr($prop) . ':' . $value;
                if (!empty($data['suffix'])) {
                    $part .= $data['suffix'];
                }

                if ($data['important']) {
                    $part .= '!important';
                }

                $part .= ';';
                $one_prop = true;

                /**
                 * Transition variations
                 */
                if ($prop == 'transition') {
                    $part .= '-webkit-transition:' . $value;
                    if (!empty($data['suffix'])) {
                        $part .= $data['suffix'];
                    }

                    if ($data['important']) {
                        $part .= '!important';
                    }

                    $part .= ';';

                    $part .= '-moz-transition:' . $value;
                    if (!empty($data['suffix'])) {
                        $part .= $data['suffix'];
                    }

                    if ($data['important']) {
                        $part .= '!important';
                    }

                    $part .= ';';
                }
                // end transition generator
            }

            $part .= '}';

            if ($one_prop) {
                $output .= $part;
            }
        }

        return $output;
    }
}
