<?php

// Exit if accessed directly.
if (!defined('ABSPATH')) exit;

/**
 * Class Rdg_Blocks_Helpers
 *
 * This class contains repetitive functions that
 * are used globally within the plugin.
 *
 * @package		RDGBLOCKS
 * @subpackage	Classes/Rdg_Blocks_Helpers
 * @author		RDGCorp
 * @since		1.0.0
 */
class Rdg_Blocks_Helpers
{
    /**
     * The blocks cache directory
     *
     * @var		array
     * @since   1.0.13
     */

    private $cache_dir;

    /**
     * The blocks cache suffix
     *
     * @var		array
     * @since   1.0.13
     */

    private $cache_suffix;

    /**
     * Our Rdg_Blocks_Settings constructor 
     * to run the plugin logic.
     *
     * @since 1.0.0
     */

    function __construct() {
        $this->cache_dir = wp_upload_dir()['basedir'].'/'.RDGBLOCKS_NAME_SLUG.'/';
        $this->cache_suffix = '-cache.log';
    }

    public function webpack($file, $buildDirectory = 'dist') {
        static $manifest;
        static $manifestPath;

        if (is_null($manifest) || $manifestPath !== $buildDirectory) {
            $manifest = json_decode(
                file_get_contents(RDGBLOCKS_PLUGIN_URL.$buildDirectory.'/manifest.json'),
                true
            );

            $manifestPath = $buildDirectory;
        }

        if (isset($manifest[$file])) {
            return RDGBLOCKS_PLUGIN_URL.trim($buildDirectory.'/'.$manifest[$file], '/');
        }

        throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
    }

    public function get_blocks_spaces($fields) {
        $styles = [];

        if (!empty($fields['top'])) {
            $styles[] = $fields['top']['top_type'].'-top: '.$fields['top']['top_space'].'rem';
        }

        if (!empty($fields['right'])) {
            $styles[] = $fields['right']['right_type'].'-right: '.$fields['right']['right_space'].'rem';
        }

        if (!empty($fields['bottom'])) {
            $styles[] = $fields['bottom']['bottom_type'].'-bottom: '.$fields['bottom']['bottom_space'].'rem';
        }

        if (!empty($fields['left'])) {
            $styles[] = $fields['left']['left_type'].'-left: '.$fields['left']['left_space'].'rem';
        }

        if (count($styles) > 0) {
            return implode('; ', $styles).';';
        }

        return '';
    }

    public function get_title($fields, $return_string = true) {
        $style = $this->get_title_sizes($fields);
        $title = (!empty($fields['title'])) ? $fields['title'] : '';
        $heading = (!empty($fields['heading'])) ? $fields['heading'] : 'span';
        
        $styles = [];
        $style[] = (!empty($fields['title_color'])) ? 'color: '.$fields['title_color'] : 'color: #3a96e0';
        $style[] = (!empty($fields['font_weight'])) ? '--font-weight: '.$fields['font_weight'] : '--font-weight: 500';
        $style[] = (!empty($fields['title_align'])) ? 'justify-content: '.$fields['title_align'] : 'justify-content: left';
        $style[] = (!empty($fields['title_color_shadow'])) ? 'text-shadow: 0px 1px 1px '.$fields['title_color_shadow'] : 'text-shadow: 0px 1px 1px #03467d';
        $style[] = (!empty($fields['padding'])) ? 'padding-bottom: '.$fields['padding'].'rem' : 'padding-bottom: 0';
    
        if (count($style) > 0 && $return_string) {
            $styles = implode('; ', $style).';';
        } else {
            $styles = $style;
        }
    
        return [$heading, $title, $styles];
    }
    
    public function get_title_sizes($fields) {
        $size = (!empty($fields['size'])) ? $fields['size'] : 3;
        $size_lg = (!empty($fields['size_lg'])) ? $fields['size_lg'] : null;
        $size_md = (!empty($fields['size_md'])) ? $fields['size_md'] : null;
        $size_sm = (!empty($fields['size_sm'])) ? $fields['size_sm'] : null;
    
        $style = [];
        
        if (!empty($size) || !empty($size_lg) || !empty($size_md) || !empty($size_sm)) {
            if (!empty($size)) {
                $last = $size;
                $style[] = '--font-size: '.$size.'rem';
                $style[] = '--line-height: '.(intval($size) + 0.5).'rem';
            } else {
                $last = 3;
                $style[] = '--font-size-lg: '.$last.'rem';
                $style[] = '--line-height-lg: '.($last + 0.5).'rem';
            }
    
            if (!empty($size_lg)) {
                $last = $size_lg;
                $style[] = '--font-size-lg: '.$size_lg.'rem';
                $style[] = '--line-height-lg: '.(intval($size_lg) + 0.5).'rem';
            } else {
                $style[] = '--font-size-lg: '.$last.'rem';
                $style[] = '--line-height-lg: '.($last + 0.5).'rem';
            }
    
            if (!empty($size_md)) {
                $last = $size_md;
                $style[] = '--font-size-md: '.$size_md.'rem';
                $style[] = '--line-height-md: '.(intval($size_md) + 0.5).'rem';
            } else {
                $style[] = '--font-size-md: '.$last.'rem';
                $style[] = '--line-height-md: '.($last + 0.5).'rem';
            }
            
            if (!empty($size_sm)) {
                $style[] = '--font-size-sm: '.$size_sm.'rem';
                $style[] = '--line-height-sm: '.(intval($size_sm) + 0.5).'rem';
            } else {
                $style[] = '--font-size-sm: '.$last.'rem';
                $style[] = '--line-height-sm: '.($last + 0.5).'rem';
            }
        }
    
        return $style;
    }

    public function get_cache_name($block_name, $post_id, $block_id, $dir = false) {
        $cache_name = $block_name.'-'.$post_id.'-'.$block_id.$this->cache_suffix;

        if (!$dir) {
            return $cache_name;
        }

        return $this->cache_dir.$cache_name;
    }

    public function set_cache_file($block_name, $cache_file, $data = null) {
        $file = New StdClass();
        $file->code = 200;
        $file->message = null;
        $file->cache_file = null;

        if (!file_exists($this->cache_dir)) {
            try {
                mkdir($this->cache_dir);
            } catch (Exception $exception) {
                if (file_exists($this->cache_dir)) {
                    unlink($this->cache_dir);
                }

                $error = $this->get_api_error('create_directory', ['block_name' => $block_name]);
                $file->code = 'create_directory';
                $file->message = $error;

                return $file;
            }
        }

        try {
            $cache = fopen($cache_file, "w");

            if (!empty($data)) {
                fwrite($cache, serialize($data));
            }

            fclose($cache);
        } catch (Exception $exception) {
            if (file_exists($cache_file)) {
                unlink($cache_file);
            }

            $error = $this->get_api_error('create_cache', ['block_name' => $block_name]);
            $file->code = 'create_cache';
            $file->message = $error;

            return $file;
        }

        $file->cache_file = $cache_file;

        return $file;
    }

    public function clear_cache($block_name, $post_id) {
        $file = New StdClass();
        $file->code = 200;
        $file->message = null;

        if (!file_exists($this->cache_dir)) {
            return $file;
        }

        $cache_list = scandir($this->cache_dir);

        $files_delete = array_map(function($cache) use ($block_name, $post_id) {
            $is_delete = strpos($cache, $block_name.'-'.$post_id.'-block-');

            if ($is_delete === 0) {
                return $cache;
            }

            return false;
        }, $cache_list);
        
        $files_delete = array_filter($files_delete);

        if (count($files_delete) > 0) {
            foreach ($files_delete as $delete) {
                try {
                    unlink($this->cache_dir.$delete);
                } catch (Exception $exception) {
                    $this->get_api_error('delete_cache', [
                        'post_id' => $post_id,
                        'block_name' => $block_name,
                        'cahe_file' => $this->cache_dir.$delete,
                        'exception' => $exception->getMessage(),
                    ]);

                    $file->code = 'delete_cache';
                }
            }
        }

        return $file;
    }

    public function get_api_data($block_name, $cache_file, $attibutes = []) {
        $data = new StdClass();
        $data->json = '';
        $data->message = '';
        $cache_exists = false;
        $cache_time_out = false;
        $cache_file = $this->cache_dir.$cache_file;

        if (!is_user_logged_in()) {
            $cache_exists = true;

            if (!file_exists($cache_file)) {
                $error = $this->get_api_error('load_cache', [
                    'block_name' => $block_name,
                    'cache_file' => $cache_file,
                ]);

                $cache_exists = false;
            }

            if ($cache_exists) {
                $cache_refresh = (isset($attibutes['cache_refresh']) && !empty($attibutes['cache_refresh'])) 
                    ? intval($attibutes['cache_refresh']) : 1;
            
                $cache_time = ((time() - filemtime($cache_file)) / 60) / 60;
                //$cache_time = 50;
        
                if (($cache_time < $cache_refresh)) {
                    $cache = file_get_contents($cache_file);
                    $data->json = unserialize($cache);
        
                    return $data;
                } else {
                    $cache_time_out = true;
                }
            }
        }

        $items = (isset($attibutes['items']) && !empty($attibutes['items'])) 
            ? intval($attibutes['items']) : 10;
        $request = (isset($attibutes['request']) && !empty($attibutes['request'])) 
            ? $attibutes['request'] : '';
        $request_method = (isset($attibutes['method']) && !empty($attibutes['method'])) 
            ? $attibutes['method'] : 'GET';
        $request_headers = (isset($attibutes['headers']) && !empty($attibutes['headers'])) 
            ? $attibutes['headers'] : [];
        $pop = (isset($attibutes['array_pop']) && $attibutes['array_pop'] == false) 
            ? false : true;

        $response_json = '';
        $response = $this->get_api_request($request, $request_method, $request_headers);

        if ($response->http_code == 200) {
            $response_json = $this->is_json($response->data);

            if ($response_json != null) {
                if ($pop) {
                    if (count($response_json) > $items) {
                        array_pop($response_json);
                    }
                }

                $data->json = $response_json;

                if (!is_user_logged_in()) {
                    $file = $this->set_cache_file($block_name, $cache_file, $response_json);

                    if ($file->cache_file == null) {
                        $data->message = $this->get_api_error('create_cache', ['block_name' => $block_name]);

                        return $data;
                    } else {
                        if ($cache_time_out) {
                            $data->message = $this->get_api_error(200, ['block_name' => $block_name]);
                        }
                    }
                }

                return $data;
            }

            $response->http_code = 'json_response';
        }

        $error = $this->get_api_error($response->http_code, [
            'block_name' => $block_name,
            'request' => $request,
            'response_json' => $response_json
        ]);

        $data->message = $error;
        
        return $data;
    }

    public function get_api_data_ajax($block_name, $attibutes = []) {
        $data = new StdClass();
        $data->json = '';
        $data->message = '';

        $items = (isset($attibutes['items']) && !empty($attibutes['items'])) 
            ? intval($attibutes['items']) : 10;
        $request = (isset($attibutes['request']) && !empty($attibutes['request'])) 
            ? $attibutes['request'] : '';
        $request_method = (isset($attibutes['method']) && !empty($attibutes['method'])) 
            ? $attibutes['method'] : 'GET';
        $request_headers = (isset($attibutes['headers']) && !empty($attibutes['headers'])) 
            ? $attibutes['headers'] : [];

        $response_json = '';
        $response = $this->get_api_request($request, $request_method, $request_headers);

        if ($response->http_code == 200) {
            $response_json = $this->is_json($response->data);

            if ($response_json != null) {
                if (count($response_json) > $items) {
                    array_pop($response_json);
                }

                $data->json = $response_json;

                return $data;
            }

            $response->http_code = 'json_response';
        }

        $error = $this->get_api_error($response->http_code, [
            'block_name' => $block_name,
            'request' => $request,
            'response_json' => $response_json
        ]);

        $data->message = $error;
        
        return $data;
    }

    public function get_api_request($request, $method, $headers = []) {
        $curl = curl_init();
        $response = new StdClass();

        curl_setopt_array($curl, [
            CURLOPT_URL => $request,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers,
        ]);

        try {
            $api_response = curl_exec($curl);
            curl_close($curl);
        } catch (Exception $exception) {
            curl_close($curl);
            $response->http_code = 'api_request';

            return $response;
        }

        $response->http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        $response->data = $api_response;
        
        return $response;
    }

    public function get_blocks_caching($blocks, $post, $content) {
        $blocks_caching = [];

        foreach ($blocks as $block) {
            if ($block->is_caching() && is_array($post) && count($post) > 0 && isset($post['_acf_nonce'])) {
                $block_name = $block->get_block_name();
    
                $block_name_exp_init = '<!-- wp:'.str_replace('/', '\/', 'acf/'.$block_name);
                $blocks_count = preg_match_all('/'.$block_name_exp_init.'/', $content, $blocks_exp, PREG_OFFSET_CAPTURE);
                    
                if ($blocks_count > 0) {
                    foreach ($blocks_exp[0] as $block_exp) {
                        $clear_block_init = substr($content, $block_exp[1], strlen($content));
                        preg_match('/\/-->/', $clear_block_init, $clear_block_end, PREG_OFFSET_CAPTURE);
                        $block_content = substr($clear_block_init, 0, $clear_block_end[0][1]).'/-->';
                        $block_parse = parse_blocks($block_content);
                        $block_attrs = $block_parse[0]['attrs'];

                        if ($block_attrs['data']['source'] == SOURCE_DATA_API) {
                            $blocks_caching[] = [
                                'name' => $block_name,
                                'custom_id' => $block_attrs['data']['custom_id'],
                                'items' => $block_attrs['data']['number_of_items'],
                            ];
                        }
                    }
                }
            }
        }

        return $blocks_caching;
    }

    public function is_json($string) {
        $encode = json_decode($string);
        $response = (json_last_error() === JSON_ERROR_NONE) ? $encode : null;

        return $response;
    }

    public function get_api_error($error, $attributes = null) {
        if ($error == 0) {
            $message = 'Invalid or unavailable URL.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 200) {
            error_log('Block: '. $attributes['block_name'].'. The cache was updated correctly.');

            return;
        }

        if ($error == 404) {
            $message = 'Resource not found.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 401) {
            $message = 'Not authorized.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }
        
        if ($error == 'json_response') {
            $message = 'Invalid data format.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 'api_request') {
            $message = 'The request could not be processed.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 'create_cache') {
            $message = 'Error trying to create cache.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 'load_cache') {
            $message = 'Error trying to load cache.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 'delete_cache') {
            $message = 'An error occurred while trying to clear the cache.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 'refresh_cache') {
            $message = 'Error trying to update cache.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        if ($error == 'create_directory') {
            $message = 'Error trying to create directory.';
            error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

            return __($message);
        }

        $message = 'The data could not be accessed, please try again later.';
        error_log(print_r(['error' => $error, 'message' => $message, 'attributes' => $attributes], true));

        return $message;
    }

    public function get_menus() {
        global $rdgb;
        $menus = [];
        $blocks = $rdgb->settings->get_blocks();

        foreach ($blocks as $block) {
            if ($block->is_config()) {
                $config = $block->get_config();
                $menus[$config['order']] = $config;
            }
        }

        ksort($menus);

        return $menus;
    }
}
