<?php
    /**
     * Trait used to generate dynamic css
     * 
     * @package Blog Bee
     * @since 1.0.0
     */
    namespace BBE;

    if( ! trait_exists( __NAMESPACE__ . '\\Dynamic_Css' ) ) {
        /**
         * Dynamic_Css Trait
         */
        trait Dynamic_Css {
            /**
             * Typography
             * 
             * @since 1.0.0
             * @param array $raw_value  The saved typography value
             * @param bool  $variable   Whether to return in variable ready value
             */
            private function get_css_typography_value( $raw_value, $variable = '' ): array {
                $font_family = $raw_value[ 'font_family' ];
                $font_weight = $this->get_font_weight( $raw_value[ 'font_weight' ] );
                $font_size = $raw_value[ 'font_size' ];
                $line_height = $raw_value[ 'line_height' ];
                $letter_spacing = $raw_value[ 'letter_spacing' ];
                $text_transform = $raw_value[ 'text_transform' ];
                $text_decoration = $raw_value[ 'text_decoration' ];
                $preset = $raw_value[ 'preset' ];
                $variable = false;
                if( $variable ) {
                    // Keeping it in case needed for future use
                    return [
                        $variable . 'size'  =>  $font_size[ 'desktop' ],
                        $variable . 'size-tablet'  =>  $font_size[ 'tablet' ],
                        $variable . 'size-mobile'  =>  $font_size[ 'mobile' ],
                        $variable . 'line-height'  =>  $line_height[ 'desktop' ],
                        $variable . 'line-height-tablet'  =>  $line_height[ 'tablet' ],
                        $variable . 'line-height-mobile'  =>  $line_height[ 'mobile' ],
                        $variable . 'letter-spacing'  =>  $letter_spacing[ 'desktop' ],
                        $variable . 'letter-spacing-tablet'  =>  $letter_spacing[ 'tablet' ],
                        $variable . 'letter-spacing-mobile'  =>  $letter_spacing[ 'mobile' ],
                        $variable . 'family'  =>  $font_family[ 'value' ],
                        $variable . 'weight'  =>  $font_weight[ 'weight' ],
                        $variable . 'style'  =>  $font_weight[ 'style' ],
                        $variable . 'text-decoration'  =>  $text_decoration,
                        $variable . 'text-transform'  =>  $text_transform,
                    ];
                } else {
                    return [
                        'desktop'   =>  [
                            '--bbe-site-font-family' =>  $font_family[ 'value' ],
                            '--bbe-site-font-weight' =>  $font_weight[ 'weight' ],
                            '--bbe-site-font-size' =>  $font_size[ 'desktop' ],
                            '--bbe-site-font-lineheight' =>  $line_height[ 'desktop' ],
                            '--bbe-site-font-letterspacing' =>  $letter_spacing[ 'desktop' ],
                            '--bbe-site-font-decoration' =>  $text_decoration,
                            '--bbe-site-font-texttransform' =>  $text_transform,
                            '--bbe-site-font-style' =>  $font_weight[ 'style' ],
                        ],
                        'tablet'   =>  [
                            '--bbe-site-font-size' =>  $font_size[ 'tablet' ],
                            '--bbe-site-font-lineheight' =>  $line_height[ 'tablet' ],
                            '--bbe-site-font-letterspacing' =>  $letter_spacing[ 'tablet' ]
                        ],
                        'mobile'   =>  [
                            '--bbe-site-font-size' =>  $font_size[ 'mobile' ],
                            '--bbe-site-font-lineheight' =>  $line_height[ 'mobile' ],
                            '--bbe-site-font-letterspacing' =>  $letter_spacing[ 'mobile' ]
                        ]
                    ];
                }
            }

            /**
             * Get font Weight
             * 
             * @since 1.0.0
             * @param   string  $weight The font weight value from typogrpahy control
             */
            private function get_font_weight( $weight ): array {
                $defualt_weight = "400" ;
                $default_style = 'regular';
                if( $weight === 'regular' ) {
                    return [
                        'weight'    =>  400,
                        'style' =>  'normal'
                    ];
                } elseif ( $weight === 'italic' ) {
                    return [
                        'weight'    =>  400,
                        'style' =>  'italic'
                    ];
                } elseif ( in_array( $weight, [ '100', '200', '300', '500', '600', '700', '800', '900' ] ) ) {
                    return [
                        'weight'    =>  $weight,
                        'style' =>  'normal'
                    ];
                } else {
                    $string_regex = preg_match( '/^(\d+)([a-z]+)$/i', $weight, $matches );
                    return [
                        'weight'    =>  $matches[ 1 ],
                        'style' =>  $matches[ 2 ]
                    ];
                }
                return [
                    'weight'    =>  $defualt_weight,
                    'style' =>  $default_style
                ];
            }

            /**
             * Generate typography dynamic css
             * 
             * @since 1.0.0
             * @param   array   $args   The arguments required to generate css
             */
            public function dynamic_typography( $args ): string {
                $expected_keys = [ 'value', 'selector', 'default' ];
                if( array_diff( $expected_keys, array_keys( $args ) ) ) return '';
                
                if( serialize( $args[ 'default' ] ) === serialize( $args[ 'value' ] ) ) return '';
                $typography = $this->get_css_typography_value( $args[ 'value' ] );
                return $this->generate_css( [
                    'selector'  =>  $args[ 'selector' ],
                    'value' =>  $typography
                ] );
            }

            /**
             * Generate css
             * 
             * @since 1.0.0
             * @param   array   $value
             */
            private function generate_css( $raw_value ): string {
                $expected_keys = [ 'selector', 'value' ];
                $hover_selector_exists = false;
                if( array_key_exists( 'hover_selector', $raw_value ) ) {
                    $hover_selector_exists = true;
                    $expected_keys[] = 'hover_selector';
                }
                if( array_diff_key( $expected_keys, array_keys( $raw_value ) ) ) return '';
                $value = $raw_value[ 'value' ];
                $selector = $raw_value[ 'selector' ];
                $hover_selector = $hover_selector_exists ? $raw_value[ 'hover_selector' ] : $selector;
                $opening_bracket = '{';
                $closing_bracket = '}';
                if( array_key_exists( 'desktop', $value ) ) {
                    $desktop = array_map( fn( $property, $property_value ) => "$property:$property_value", array_keys( $value[ 'desktop' ] ), $value[ 'desktop' ] );
                    $tablet = array_map( fn( $property, $property_value ) => "$property:$property_value", array_keys( $value[ 'tablet' ] ), $value[ 'tablet' ] );
                    $mobile = array_map( fn( $property, $property_value ) => "$property:$property_value", array_keys( $value[ 'mobile' ] ), $value[ 'mobile' ] );
                    $tablet_width = '@media(max-width: 768px)';
                    $mobile_width = '@media(max-width: 620px)';
                    $css = '';
                    $css .= $selector . $opening_bracket . implode( ';', $desktop ) . $closing_bracket;
                    $css .= $tablet_width . $opening_bracket . $selector . $opening_bracket . implode( ';', $tablet ) . $closing_bracket . $closing_bracket;
                    $css .= $mobile_width . $opening_bracket . $selector . $opening_bracket . implode( ';', $mobile ) . $closing_bracket . $closing_bracket;
                    return $css;
                } elseif ( array_key_exists( 'initial', $value ) ) {
                    $css_arr = [];
                    foreach( $value as $type => $color ) {
                        $css_arr[ $type ] = array_map( fn( $property, $property_value ) => "$property: $property_value", array_keys( $color ), $color );
                    }
                    $initial = $css_arr[ 'initial' ];
                    $hover = $css_arr[ 'hover' ];
                    $css = '';
                    $css .= $selector . $opening_bracket . implode( ';', $initial ) . $closing_bracket;
                    $css .= $hover_selector . $opening_bracket . implode( ';', $hover ) . $closing_bracket;
                    return $css;
                } else {
                    $css = array_map( fn( $property, $property_value ) => "$property: $property_value", array_keys( $value ), $value );
                    return $selector . $opening_bracket . implode( ';', $css ) . $closing_bracket;
                }
            }

            /**
             * Generate border dynamic css
             * 
             * @since 1.0.0
             * @param   array   $args   The arguments required to generate css
             */
            public function dynamic_border( $args ): string {
                $expected_keys = [ 'value', 'selector', 'default' ];
                if( array_diff( $expected_keys, array_keys( $args ) ) ) return '';

                $property = isset( $args[ 'property' ] ) ? $args[ 'property' ] : 'border';
                
                if( serialize( $args[ 'default' ] ) === serialize( $args[ 'value' ] ) ) return '';
                $value = $args[ 'value' ];
                $border = [];
                
                if( isset( $value[ 'color' ] ) ) {
                    $color_args = [
                        'value' =>  $value[ 'color' ],
                        'type'  =>  $value[ 'type' ]
                    ];
                    $border = array_merge( $border, $this->get_color_css( $color_args, $property . '-color' ) );
                }
                if( isset( $value[ 'style' ] ) ) $border[ $property . '-style' ] = $value[ 'style' ];
                if( isset( $value[ 'width' ] ) ) {
                    $width = $value[ 'width' ];
                    unset( $width[ 'link' ] );
                    $border[ $property . '-width' ] = implode( 'px ', $width ) . 'px';
                }

                return $this->generate_css( [
                    'selector'  =>  $args[ 'selector' ],
                    'value' =>  $border
                ] );
            }

            /**
             * Generate number dynamic css
             * 
             * @since 1.0.0
             * @param   array   $args   The arguments required to generate css
             */
            public function dynamic_number( $args ): string {
                $expected_keys = [ 'value', 'selector', 'default', 'property' ];
                if( array_diff( $expected_keys, array_keys( $args ) ) ) return '';
                
                if( serialize( $args[ 'default' ] ) === serialize( $args[ 'value' ] ) ) return '';
                $value = $args[ 'value' ];
                if( is_array( $args[ 'value' ] ) && array_key_exists( 'desktop', $args[ 'value' ] ) ) {
                    $number = [
                        'desktop'   =>  [
                            $args[ 'property' ] =>  $value[ 'desktop' ]
                        ],
                        'tablet'   =>  [
                            $args[ 'property' ] =>  $value[ 'tablet' ]
                        ],
                        'mobile'   =>  [
                            $args[ 'property' ] =>  $value[ 'mobile' ]
                        ],
                    ];
                } else {
                    $number = [
                        $args[ 'property' ] =>  $value
                    ];
                }

                return $this->generate_css( [
                    'selector'  =>  $args[ 'selector' ],
                    'value' =>  $number
                ] );
            }

            /**
             * Generate box shadow dynamic css
             * 
             * @since 1.0.0
             * @param   array   $args   The arguments required to generate css
             */
            public function dynamic_box_shadow( $args ): string {
                $expected_keys = [ 'value', 'selector', 'default' ];
                if( array_diff( $expected_keys, array_keys( $args ) ) ) return '';
                
                $value = $args[ 'value' ];
                if( serialize( $args[ 'default' ] ) === serialize( $value ) ) return '';

                $property = isset( $args[ 'property' ] ) ? $args[ 'property' ] : 'box-shadow';
                $enable = $value[ 'enable' ];
                if( ! $enable ) {
                    return $this->generate_css( [
                        'selector'  =>  $args[ 'selector' ],
                        'value' =>  [ $property => 'none' ]
                    ] );
                }
                $offsetx = $value[ 'offsetx' ] . 'px';
                $offsety = $value[ 'offsety' ] . 'px';
                $inset = $value[ 'inset' ];
                $color = $value[ 'color' ];
                if( strpos( $color, '--bbe-' ) !== false ) {
                    $color = 'var(' . $color . ')';
                }
                $blur = $value[ 'blur' ] . 'px';
                $spread = $value[ 'spread' ] . 'px';
                $type = $inset ? 'inset' : '';
                $box_shadow = [
                    $property    =>   "$type $offsetx $offsety $blur $spread $color"
                ];
                
                return $this->generate_css( [
                    'selector'  =>  $args[ 'selector' ],
                    'value' =>  $box_shadow
                ] );
            }

            /**
             * Generate dimension dynamic css
             * 
             * @since 1.0.0
             * @param   array   $args   The arguments required to generate css
             */
            public function dynamic_dimension( $args ): string {
                $expected_keys = [ 'value', 'selector', 'default', 'property' ];
                if( array_diff( $expected_keys, array_keys( $args ) ) ) return '';
                
                $value = $args[ 'value' ];
                if( serialize( $args[ 'default' ] ) === serialize( $value ) ) return '';
                $property = $args[ 'property' ];
                if( array_key_exists( 'desktop', $value ) ) {
                    $desktop = $value[ 'desktop' ];
                    unset( $desktop[ 'link' ] );
                    $tablet = $value[ 'tablet' ];
                    unset( $tablet[ 'link' ] );
                    $mobile = $value[ 'mobile' ];
                    unset( $mobile[ 'link' ] );
                    $dimension = [
                        'desktop'   =>  [
                            $property   =>  implode( 'px ', $desktop ) . 'px'
                        ],
                        'tablet'   =>  [
                            $property   =>  implode( 'px ', $tablet ) . 'px'
                        ],
                        'mobile'   =>  [
                            $property   =>  implode( 'px ', $mobile ) . 'px'
                        ],
                    ];
                } else {
                    unset( $value[ 'link' ] );
                    $dimension = [
                        $property   =>  implode( 'px ', $value ) . 'px'
                    ];
                }

                return $this->generate_css( [
                    'selector'  =>  $args[ 'selector' ],
                    'value' =>  $dimension
                ] );
            }

            /**
             * Get background image css
             * 
             * @since 1.0.0
             * @param array $image_args The arguments of image
             */
            private function get_color_css( $color_args, $property ) {
                $value = $color_args[ 'value' ];
                if( $color_args[ 'type' ] === 'image' ) {
                    if( isset( $color_args[ 'image' ] ) ) {
                        $image_properties = $color_args[ 'image' ];
                        $background_properties = [];
                        $background_image = '';
                        if( array_key_exists( 'overlay', $image_properties ) ) {
                            $overlay = $image_properties[ 'overlay' ];
                            if( strpos( $overlay, '--bbe-' ) !== false ) {
                                $overlay = 'var(' . $overlay . ')';
                            }
                            $background_image .= $overlay . ',';
                        }
                        if( array_key_exists( 'url', $image_properties ) ) {
                            $background_image .= ' url('. $image_properties[ 'url' ] .')';
                        }
                        if( $background_image ) {
                            $background_properties[ 'background-image' ] = $background_image;
                        }
                        if( array_key_exists( 'position', $image_properties ) ) $background_properties[ 'background-position' ] = $image_properties[ 'position' ];
                        if( array_key_exists( 'attachment', $image_properties ) ) $background_properties[ 'background-attachment' ] = $image_properties[ 'attachment' ];
                        if( array_key_exists( 'repeat', $image_properties ) ) $background_properties[ 'background-repeat' ] = $image_properties[ 'repeat' ];
                        if( array_key_exists( 'size', $image_properties ) ) $background_properties[ 'background-size' ] = $image_properties[ 'size' ];
                        return $background_properties;
                    } else {
                        return [];
                    }
                } else {
                    if( strpos( $value, '--bbe-' ) !== false ) {
                        $value = 'var(' . $value . ')';
                    }
                    return [
                        $property   =>  $value
                    ];
                }
            }

            /**
             * Generate color dynamic css
             * 
             * @since 1.0.0
             * @param   array   $args   The arguments required to generate css
             */
            public function dynamic_color( $args ): string {
                $expected_keys = [ 'value', 'selector', 'default', 'property' ];
                $hover_selector_exists = false;
                if( array_diff( $expected_keys, array_keys( $args ) ) ) return '';
                
                $value = $args[ 'value' ];
                if( serialize( $args[ 'default' ] ) === serialize( $value ) ) return '';
                $property = $hover_property = $args[ 'property' ];
                if( array_key_exists( 'initial', $value ) ) {
                    if( strpos( $property, '--bbe-' ) !== false ) {
                        $hover_property = $property . '-hover';
                    }
                    $initial = $value[ 'initial' ];
                    $hover = $value[ 'hover' ];
                    $color = [
                        'initial'   =>  $this->get_color_css( $initial, $property ),
                        'hover'   =>  $this->get_color_css( $hover, $hover_property )
                    ];
                    $hover_selector_exists = true;
                } else {
                    $color = $this->get_color_css( $value, $property );
                }

                $generate_css_args = [
                    'selector'  =>  $args[ 'selector' ],
                    'value' =>  $color
                ];
                if( $hover_selector_exists ) {
                    if( isset( $args[ 'hover_selector' ] ) ) {
                        $generate_css_args[ 'hover_selector' ] = $args[ 'hover_selector' ];
                    } else {
                        $generate_css_args[ 'hover_selector' ] = $args[ 'selector' ] . ':hover';
                    }
                }

                return $this->generate_css( $generate_css_args );
            }
        }
    }