<?php

if ( !defined( 'ABSPATH' ) ) {

    exit;
}

if ( !class_exists( 'Pricely_Views_CSS' ) ) {

    require_once 'view-css-util.php';


    require_once 'view-css-countdown/view-css-countdown.php';
    require_once 'view-css-price-table.php';
    require_once 'view-css-label.php';

    class Pricely_Views_CSS {

        private static $instance;
        private $css_pre;
        private $css_dir;
        private $css_file_name;
        private $css_composers;

        public static function get_instance(): self {

            if ( !self::$instance ) {

                self::$instance = new self();
            }

            return self::$instance;
        }

        public function __construct() {

            $this->css_pre = 'prly-css-';
            $this->css_dir = '/pricely';
            $this->css_file_name = '/custom.css';
        }

        public function is_using_external_css() {

            $default = 'no';

            $opt = $this->get_options( 'using_external_css', $default );

            return ('yes' == $opt);
        }

        public function get_custom_css_ver() {

            $default = 0;

            return $this->get_options( 'revision', $default );
        }

        public function get_custom_css_url() {

            $upload_dir = wp_upload_dir();

            return $upload_dir[ 'baseurl' ] . $this->css_dir . $this->css_file_name;
        }

        public function get_css_class( $ui_id, $ui_type ) {

            return $this->css_pre . $ui_type . '-' . $ui_id;
        }

        public function get_css_selector( $ui_id, $ui_type, $prefix = '', $suffix = '' ) {

            $ui_selector = '.' . $this->css_pre . $ui_type . '-' . $ui_id;

            return $prefix . $ui_selector . $suffix;
        }

        public function get_css() {

            $options = $this->load_options();

            return $this->compile_css( $this->compose_css( $options ), $options );
        }

        public function save_css( $options ) {

            if ( !('yes' == $options[ 'use_external_css' ]) ) {

                return false;
            }

            global $wp_filesystem;

            if ( !is_a( $wp_filesystem, 'WP_Filesystem_Base' ) ) {

                $creds = request_filesystem_credentials( site_url() );

                WP_Filesystem( $creds );
            }

            $upload_dir = wp_upload_dir();

            $pricely_dir = $upload_dir[ 'basedir' ] . $this->css_dir;

            if ( !file_exists( $pricely_dir ) ) {

                wp_mkdir_p( $pricely_dir );
            }

            $css_file_name = trailingslashit( $pricely_dir ) . $this->css_file_name;

            $css_content = $this->compile_css( $this->compose_css( $options ), $options );

            return $wp_filesystem->put_contents( $css_file_name, $css_content, FS_CHMOD_FILE );
        }

        private function compose_css( $options ) {

            $css = array();

            foreach ( $this->load_css_composers() as $css_composer ) {

                if ( !method_exists( $css_composer, 'compose_css' ) ) {

                    continue;
                }

                $css = $css_composer->compose_css( $css, $options );
            }

            if ( !is_array( $css ) ) {

                return array();
            }

            return $css;
        }

        private function compile_css( $css, $options ) {

            $css_content = '';

            foreach ( $css as $css_selector => $raw_css_props ) {

                $css_props = $this->sanitize_css_props( $raw_css_props );

                if ( !count( $css_props ) ) {

                    continue;
                }

                $selector = esc_attr( $css_selector );

                if ( empty( $selector ) ) {

                    continue;
                }

                $css_content .= $selector . '{' . $this->compile_css_props( $css_props ) . '}';
            }

            if ( isset( $options[ 'custom_css' ] ) && !empty( $options[ 'custom_css' ] ) ) {

                $css_content .= $options[ 'custom_css' ];
            }

            return $this->minify_css( $css_content );
        }

        private function compile_css_props( $css_props ) {

            $css_prop_content = '';

            foreach ( $css_props as $css_prop_key => $css_prop ) {

                $prop_key = esc_attr( $css_prop_key );
                $prop = esc_attr( $css_prop );

                if ( empty( $prop_key ) ) {

                    continue;
                }

                if ( '' == $prop ) {

                    continue;
                }

                $css_prop_content .= $prop_key . ': ' . $prop . ';';
            }

            return $css_prop_content;
        }

        private function load_css_composers() {

            if ( !is_null( $this->css_composers ) ) {

                return $this->css_composers;
            }

            $this->css_composers = array();

            foreach ( $this->register_css_composers() as $key => $css_composer ) {

                if ( !class_exists( $css_composer ) ) {

                    continue;
                }

                if ( method_exists( $css_composer, 'get_instance' ) ) {

                    $this->css_composers[ $key ] = $css_composer::get_instance();
                } else {

                    $this->css_composers[ $key ] = new $css_composer();
                }
            }

            return $this->css_composers;
        }

        private function register_css_composers() {

            $ui_css_composers = array(
                'Pricely_Views_CSS_CountDown',
                'Pricely_Views_CSS_Price_Table',
                'Pricely_Views_CSS_Label'
            );

            return apply_filters( 'pricely_register-css-composers', $ui_css_composers );
        }

        private function sanitize_css_props( $css_props ) {

            $sanitized_css_props = array();

            foreach ( $css_props as $css_prop_key => $css_prop ) {

                $prop_key = esc_attr( $css_prop_key );
                $prop = esc_attr( $css_prop );

                if ( empty( $prop_key ) ) {

                    continue;
                }

                if ( '' == $prop ) {
                    continue;
                }

                $sanitized_css_props[ $prop_key ] = $prop;
            }

            return $sanitized_css_props;
        }

        private function minify_css( $css_content ) {

            $replacements = array(
                array(
                    'search' => '/\s+/',
                    'replace_with' => ' '
                ),
                array(
                    'search' => '/;(?=\s*})/',
                    'replace_with' => ''
                ),
                array(
                    'search' => '/(,|:|;|\{|}|\*\/|>) /',
                    'replace_with' => '$1'
                ),
                array(
                    'search' => '/ (,|;|\{|})/',
                    'replace_with' => '$1'
                ),
                array(
                    'search' => '/(:| )0\.([0-9]+)(%|em|ex|px|in|cm|mm|pt|pc)/i',
                    'replace_with' => '${1}.${2}${3}'
                ),
                array(
                    'search' => '/(:| )(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/i',
                    'replace_with' => '${1}0'
                ),
            );

            foreach ( $replacements as $replacement ) {

                $search = $replacement[ 'search' ];
                $replace_with = $replacement[ 'replace_with' ];

                $css_content = preg_replace( $search, $replace_with, $css_content );
            }

            return trim( $css_content );
        }

        private function get_options( $option_key, $default ) {

            $pricely = Pricely::get_instance();

            return $pricely->get_options( $option_key, $default );
        }

        private function load_options() {

            $pricely = Pricely::get_instance();

            return $pricely->load_options();
        }

    }

}

