<?php
    /**
     * Sections base
     * 
     * @package Blog Bee
     * @since 1.0.0
     */
    namespace BBE\Customizer\Section;

    use WP_Customize_Section;
    use BBE\Customizer\Customizer_Defaults as Customizer_Defaults;
    use BBE\Customizer\Sanitize_Functions as Sanitize_Functions;
    use BBE\Dynamic_Css as Dynamic_Css;
    use BBE\Customizer\Base as Base;
    use BBE\Customizer\Panels as Panels;

    use function get_theme_mod;

    interface Section_Interface {

        /**
         * Dynamic css
         * 
         * @since 1.0.0
         */
        public function render_dynamic_css();
    }

    if( ! class_exists( __NAMESPACE__ . '\\Section' ) ) {
        /**
         * Section Class
         */
        abstract class Section implements Section_Interface {
            /**
             * Using trait 
             */
            use Customizer_Defaults;
            use Sanitize_Functions;
            use Dynamic_Css;

            /**
             * Section id
             * 
             * @since 1.0.0
             */
            public static $id = '';

            /**
             * Manager instance
             * 
             * @see WP_Customizer_Manager
             * @since 1.0.0
             */
            public $manager = null;

            /**
             * Stores all classes that extend this class
             * 
             * @since 1.0.0
             */
            protected static $sections = [];

            /**
             * Section id
             * 
             * @var string
             * @since 1.0.0
             */
            public $section = '';

            /**
             * Common control args
             * 
             * @var array
             * @since 1.0.0
             */
            public $common = [];

            /**
             * Tab
             * 
             * @var string
             * @since 1.0.0
             */
            public $tab = 'general';

            /**
             * Dynamic css args
             * 
             * @var array
             * @since 1.0.0
             */
            public $dynamic_css_args = [];

            /**
             * Dynamic styles
             * 
             * @var array
             * @since 1.0.0
             */
            public $dynamic_styles = [];

            /**
             * Default values
             * 
             * @var array
             * @since 1.0.0
             */
            public $defaults = [];

            /**
             * Section instance
             * 
             * @since 1.0.0
             */
            protected static $instances = [];

            /**
             * Get section instance
             * All classes that extend this class will have singleton pattern
             * 
             * @since 1.0.0
             */
            public static function get_instance() {
                $class = static::class;

                if( ! isset( self::$instances[ $class ] ) ) self::$instances[ $class ] = new static();

                return self::$instances[ $class ];
            }

            /**
             * Instantiate class
             * 
             * @since 1.0.0
             */
            public function __construct() {
                self::$sections[ static::$id ] = static::class;
                $this->set_defaults();
                add_action( 'init', function(){
                    $this->set_dynamic_style_func();
                } );
                add_action( 'customize_register', [ $this, 'init' ] );
            }

            /**
             * Get all extended classes
             * This function is used for autoloading dynamic css and preview js object
             * 
             * @since 1.0.0
             */
            public static function get_all_registered_sections() {
                return self::$sections;
            }

            /**
             * Init
             * 
             * @since 1.0.0
             */
            public function init( $wp_customize ) {
                $this->manager = $wp_customize;
                $this->register_panels();
                $this->register_controls();
                $this->register_partials();
            }

            /**
             * Register Panels
             * 
             * @since 1.0.0
             */
            private function register_panels(): void {
                $panels = Panels::get_instance()->get_panels();
                if( ! empty( $panels ) ) {
                    foreach( $panels as $panel_id => $panel_args ) {
                        $this->manager->add_panel( $panel_id, $panel_args );
                    }
                }
            }

            /**
             * Get dynamic styles functions
             * 
             * @since 1.0.0
             */
            public function set_dynamic_style_func() {
                $this->dynamic_styles = [
                    'box-shadow'    =>  [ $this, 'dynamic_box_shadow' ],
                    'typography'    =>  [ $this, 'dynamic_typography' ],
                    'bbe-number'    =>  [ $this, 'dynamic_number' ],
                    'border'    =>  [ $this, 'dynamic_border' ],
                    'dimension'    =>  [ $this, 'dynamic_dimension' ],
                    'bbe-color'    =>  [ $this, 'dynamic_color' ],
                ];
            }

            /**
             * Register controls
             * 
             * @since 1.0.0
             */
            abstract protected function register_controls();

            /**
             * Get settings
             * 
             * @since 1.0.0
             */
            abstract protected function get_settings( $id = '' );

            /**
             * Get controls
             * 
             * @since 1.0.0
             */
            abstract public function get_controls( $id = '' );

            /**
             * Set controls
             * 
             * @since 1.0.0
             */
            abstract public function set_defaults();

            /**
             * Get controls
             * 
             * @since 1.0.0
             */
            abstract public function render_html();

            /**
             * Dynamic css args
             * 
             * @since 1.0.0
             */
            abstract public function get_dynamic_css_args();

            /**
             * Add partial
             * A method to be overriden by child classes
             * 
             * @since 1.0.0
             */
            protected function register_partials(){}

            /**
             * Add Section
             * 
             * @since 1.0.0
             */
            protected function add_section( $id ) {
                $this->section = $id;
                $section = $this->get_controls( $id );
                $this->manager->add_section( new BBE_Customzie_Section( $this->manager, $id, $section ) );
                $this->common = [
                    'section'   =>  $id
                ];
            }

            /**
             * Add setting
             * 
             * @since 1.0.0
             */
            protected function add_setting( $id ) {
                $setting = $this->get_settings( $id );
                $this->manager->add_setting( $id, $setting );
            }

            /**
             * Add control
             * 
             * @since 1.0.0
             */
            protected function add_control( $id ) {
                $setting = $this->get_settings( $id );
                $this->common[ 'tab' ] = $this->tab;
                $this->common[ 'section' ] = $this->section;
                $control = array_merge( $this->get_controls( $id ), $this->common );
                $default_types = [ 'text', 'checkbox', 'textarea', 'radio', 'select', 'dropdown-pages', 'email', 'url', 'number', 'hidden', 'date' ];

                $this->manager->add_setting( $id, $setting );

                if( in_array( $control[ 'type' ], $default_types ) ) :
                    $this->manager->add_control( $id, $control );
                else:
                    $this->get_custom_control( $id, $control );
                endif;
            }

            /**
             * Get custom control
             * Dynamically instantiate class based on control type
             * 
             * @since 1.0.0
             * @param string    $id     The control id
             * @param array     $control    The control arguments
             */
            protected function get_custom_control( $id, $control ) {
                $all_custom_controls = Base::get_all_custom_controls();
                if( isset( $all_custom_controls[ $control[ 'type' ] ] ) ) :
                    $this->manager->add_control( new $all_custom_controls[ $control[ 'type' ] ]( $this->manager, $id, $control ) );
                else:
                    $control[ 'type' ] = 'text';
                    $this->manager->add_control( $id, $control );
                endif;
            }

            /**
             * Get dynamic css
             * 
             * @since 1.0.0
             * @param   bool    $add_type   
             */
            public function get_dynamic_css( $add_type = false ) {
                $dynamic_css_args = $this->get_dynamic_css_args();
                if( ! $dynamic_css_args ) return [];
                if( $add_type ) {
                    $configs = [];
                    foreach( $dynamic_css_args as $id => $args ) {
                        $control_args = $this->get_controls( $id );
                        $args[ 'type' ] = $control_args[ 'type' ];
                        $configs[ $id ] = $args;
                    }
                    return $configs;
                } else {
                    return $dynamic_css_args;
                }
            }

            /**
             * Render dynamic css
             * 
             * @return css
             * @since 1.0.0
             */
            public function render_dynamic_css() {
                $dynamic_css = [];
                $dynamic_css_args = $this->get_dynamic_css_args();
                if( ! $dynamic_css_args ) return [];
                foreach( $dynamic_css_args as $id => $args ) {
                    $control_args = $this->get_controls( $id );
                    if( isset( $this->dynamic_styles[ $control_args[ 'type' ] ] ) ) {
                        $css = call_user_func( $this->dynamic_styles[ $control_args[ 'type' ] ], $args );
                        if( ! $css ) continue;
                    } else {
                        continue;
                    }
                    $dynamic_css[ $id ] = $css;
                }
                $replaced_id = str_replace( '-', '_', static::$id );
                return apply_filters( "{$replaced_id}_dynamic_css_filter", $dynamic_css );
            }
        }
    }