<?php

class Bug_Monitor_Dashboard {

      public static $messages = array();

      public static function init(){
            add_submenu_page(
                  'tools.php',
                  __('BugMonitor', 'bug-monitor'),
                  __('BugMonitor', 'bug-monitor'),
                  'manage_options',
                  'bug-monitor',
                  array(__CLASS__, 'dashboard'),
                  4
            );

            add_action('admin_enqueue_scripts', function($hook){
                  if ($hook == 'tools_page_bug-monitor'){
                        add_action('admin_notices', function(){
                              remove_all_actions('admin_notices');
                              remove_all_actions('all_admin_notices');
                        }, -PHP_INT_MAX);

                        $css_ver = md5_file(BUG_MONITOR_PLUGIN_DIR . 'assets/admin.css');
                        $js_ver = md5_file(BUG_MONITOR_PLUGIN_DIR . 'assets/admin.js');
                        wp_enqueue_style('bug-monitor', BUG_MONITOR_PLUGIN_URL . 'assets/admin.css', array(), $css_ver);
                        wp_enqueue_script('bug-monitor', BUG_MONITOR_PLUGIN_URL . 'assets/admin.js', array('jquery'), $js_ver, true);
                        wp_localize_script('bug-monitor', 'bug_monitor', array('session_url' => add_query_arg('bm-session','SESSIONID',home_url()), 'nonce' => wp_create_nonce('bug-monitor-ajax'), 'counts' => Bug_Monitor_Log::get_counts(), 'count_cap' => 1000, 'i18n' => self::i18n()));
                  }
            });

            add_action('admin_init', function(){
                  if (Bug_Monitor::check_option('activated', '-1', '=')) {
                        self::add_message(
                              sprintf(esc_html__('API connection error. Click %shere%s to reconnect Bug Monitor API', 'bug-monitor'), '<a href="' . add_query_arg(array('site' => home_url(), 'site-key' => Bug_Monitor_API::get_site_key(), 'plugin' => 'bugmonitor', 'redirect_to' => Bug_Monitor_Helper::get_dashbord_url()), 'https://musthaveplugins.com/my-account/api/connect/') . '">', '</a>'),
                              'warning'
                        );
                  }
                  else if (Bug_Monitor::check_option('activated', '1', '!=') && Bug_Monitor::check_option('promo', '1', '!=')) {
                        self::add_message(
                              sprintf(esc_html__('Your site is not connected yet. Click %shere%s to connect your site to the Bug Monitor API, which will enable you to use all features.', 'bug-monitor'), '<a href="' . add_query_arg(array('site' => home_url(), 'site-key' => Bug_Monitor_API::get_site_key(), 'plugin' => 'bugmonitor', 'redirect_to' => Bug_Monitor_Helper::get_dashbord_url()), 'https://musthaveplugins.com/my-account/api/connect/') . '">', '</a>'),
                              'warning'
                        );
                  }
                  $api_error = Bug_Monitor::get_option('api-error');
                  if (!empty($api_error)){
                        self::add_message(
                              esc_html($api_error),
                              'error'
                        );
                  }
            });
            add_action('admin_bar_menu', array(__CLASS__, 'toolbar'), 50);
            add_filter('plugin_action_links_' . BUG_MONITOR_PLUGIN_SLUG, array(__CLASS__, 'plugin_links'));
            add_filter('plugin_row_meta', array(__CLASS__, 'plugin_row_meta'), 10, 2);
            add_action('admin_notices', array(__CLASS__, 'show_notices'));
      }

      public static function dashboard(){
            include_once BUG_MONITOR_PLUGIN_DIR . 'templates/dashboard.tpl.php';
      }

      public static function get_category($category){
            $categories = array(
                  'network' => __('Network', 'bug-monitor'),
                  'seo' => __('SEO', 'bug-monitor'),
                  'ux' => __('UX', 'bug-monitor'),
                  'ui' => __('UI', 'bug-monitor'),
                  'js' => __('JavaScript', 'bug-monitor'),
                  'webvitals' => __('Web Vitals', 'bug-monitor'),
                  'functional' => __('Functional', 'bug-monitor'),
                  'php' => __('WordPress', 'bug-monitor')
            );

            return $categories[$category];
      }

      public static function get_title($type){
            $titles = array(
                  'network/http' => __('HTTP Error', 'bug-monitor'),
                  'network/mixed_content' => __('Mixed Content', 'bug-monitor'),
                  'network/csp' => __('CSP Violation', 'bug-monitor'),
                  'network/insecure' => __('Insecure Connection', 'bug-monitor'),
                  'seo/title' => __('Title', 'bug-monitor'),
                  'seo/description' => __('Meta Description', 'bug-monitor'),
                  'seo/image' => __('Image ALT Issue', 'bug-monitor'),
                  'ux/non_responsive_element' => __('Unresponsive Element', 'bug-monitor'),
                  'ux/slow_response' => __('Slow Response', 'bug-monitor'),
                  'ux/bounce_rate' => __('High Bounce Rate', 'bug-monitor'),
                  'ux/bounce' => __('High Bounce Rate', 'bug-monitor'),
                  'ui/too_close_clickable' => __('Too Close Clickable Elements', 'bug-monitor'),
                  'ui/hard_read_text' => __('Hard to Read Text', 'bug-monitor'),
                  'ui/layout' => __('Layout Issue', 'bug-monitor'),
                  'ui/content_obstruction' => __('Content Obstruction', 'bug-monitor'),
                  'ui/font' => __('Font Error', 'bug-monitor'),
                  'js/error' => __('JavaScript Error', 'bug-monitor'),
                  'webvitals/lcp' => __('LCP Needs Improvement', 'bug-monitor'),
                  'webvitals/fcp' => __('FCP Needs Improvement', 'bug-monitor'),
                  'webvitals/cls' => __('CLS', 'bug-monitor'),
                  'functional/non_responsive_button' => __('Unresponsive Link/Button', 'bug-monitor'),
                  'functional/form_submission' => __('Possible Form Submission Issue', 'bug-monitor'),
                  'functional/form_abandonment' => __('Form Abandonment Issue', 'bug-monitor'),
                  'functional/broken_link' => __('Broken Link', 'bug-monitor'),
                  'php/error' => __('PHP Error', 'bug-monitor'),
                  'php/warning' => __('PHP Warning', 'bug-monitor'),
                  'php/redirect_loop' => __('Redirect loop', 'bug-monitor'),
                  'php/malicious_redirect' => __('Malicious redirect', 'bug-monitor'),
                  'php/email_sending_error' => __('Email sending error', 'bug-monitor'),
            );

            return isset($titles[$type]) ? $titles[$type] : '';
      }

      public static function get_error_insight_link($type){
            switch ($type){
                  case 'network/http':
                        $path = 'http-error';
                        break;
                  case 'network/mixed_content':
                        $path = 'mixed-content';
                        break;
                  case 'network/csp':
                        $path = 'csp-violation';
                        break;
                  case 'network/insecure':
                        $path = 'insecure-connection';
                        break;
                  case 'seo/title':
                  case 'seo/description':
                        $path = 'title-and-meta-issues';
                        break;
                  case 'seo/image':
                        $path = 'image-alt-issue';
                        break;
                  case 'ux/non_responsive_element':
                        $path = 'unresponsive-element-issue';
                        break;
                  case 'ux/slow_response':
                        $path = 'slow-response-issue';
                        break;
                  case 'ux/bounce_rate':
                        $path = 'high-bounce-rate-issue';
                        break;
                  case 'ui/too_close_clickable':
                        $path = 'too-close-clickable-elements';
                        break;
                  case 'ui/hard_read_text':
                        $path = 'hard-to-read-text';
                        break;
                  case 'ui/layout':
                        $path = 'layout-issues';
                        break;
                  case 'ui/content_obstruction':
                        $path = 'content-obstruction';
                        break;
                  case 'js/error':
                        $path = 'javascript-error';
                        break;
                  case 'webvitals/lcp':
                  case 'webvitals/fcp':
                  case 'webvitals/cls':
                        $path = 'webvitals-issues';
                        break;
                  case 'functional/non_responsive_button':
                        $path = 'unresponsive-link-button';
                        break;
                  case 'functional/form_submission':
                        $path = 'form-submission-issue';
                        break;
                  case 'functional/form_abandonment':
                        $path = 'form-abandonment-issue';
                        break;
                  case 'functional/broken_link':
                        $path = 'broken-link';
                        break;
                  case 'php/error':
                  case 'php/warning':
                        $path = 'php-error-warning';
                        break;
                  case 'php/redirect_loop':
                        $path = 'redirect-loop';
                        break;
                  case 'php/malicious_redirect':
                        $path = 'malicious-redirect';
                        break;
                  case 'php/email_sending_error':
                        $path = 'email-errors';
                        break;
                  default:
                        $path = '';

            }

            return 'https://bug-monitor.com/error-insights/' . trailingslashit($path);
      }

      public static function get_level($level){
            $levels = array(
                  'critical' => __('Critical Error', 'bug-monitor'),
                  'error' => __('Error', 'bug-monitor'),
                  'warning' => __('Warning', 'bug-monitor'),
                  'info' => __('Info', 'bug-monitor'),
            );

            return $levels[$level];
      }

      public static function get_timestamps($data){
            if (empty($data['timestamps'])){
                  return;
            }

            // Get the timezone string from WordPress
            $timezone_string = wp_timezone_string();
            $timezone = new DateTimeZone($timezone_string);

            if (count($data['timestamps']) == 1){
                  return wp_date(get_option('date_format') . ' ' . get_option('time_format'), strtotime($data['timestamps'][0]), $timezone);
            }
            else {
                  usort($data['timestamps'], function($a, $b) {
                      return strtotime($a) - strtotime($b);
                  });

                  $first = array_shift($data['timestamps']);
                  $last = array_pop($data['timestamps']);

                  if (date('z', strtotime($first)) == date('z', strtotime($last))){
                        return date(get_option('date_format'), strtotime($last));
                  }

                  return wp_date(get_option('date_format'), strtotime($first), $timezone) . ' - ' . wp_date(get_option('date_format'), strtotime($last), $timezone);
            }
      }

      public static function add_message($message, $type = 'info'){
            self::$messages[] = array(
                  'type' => $type,
                  'text' => $message
            );
      }
      public static function plugin_links($links){
            $links[] = '<a href="' . Bug_Monitor_Helper::get_dashbord_url() . '">' . __('Settings', 'bug-monitor') . '</a>';
        	return $links;
      }
      public static function plugin_row_meta($links, $file){
            if ($file == BUG_MONITOR_PLUGIN_SLUG) {
                  $links[] = '<a href="' . esc_url(add_query_arg('bug-monitor-check-for-updates','1', admin_url('plugins.php'))) . '">' . __('Check for updates', 'bug-monitor') . '</a>';
            }
            return $links;
      }

      public static function get_description($event){
            switch ($event['type']){
                  case 'network/http':
                        return sprintf(__('There is a network error for resource %s.', 'bug-monitor'), esc_url($event['details']['url']));
                  case 'network/mixed_content':
                        return sprintf(__('Browser blocked loading mixed content. Resource %s is using HTTP on a HTTPS page.', 'bug-monitor'), esc_url($event['details']['url']));
                  case 'network/csp':
                        return sprintf(__('Resource %s has been blocked, because it violates Content Security Policy.', 'bug-monitor'), esc_url($event['details']['url']));
                  case 'network/insecure':
                        return sprintf(__('The site was loaded through an insecure connection without SSL encryption. Beyond security issues, this can cause slowdowns and harm SEO.', 'bug-monitor'), esc_url($event['details']['url']));
                  case 'seo/title':
                        switch ($event['details']['issue']){
                              case 'missing':
                              case 'empty':
                                    return esc_html__('<title> tag is missing', 'bug-monitor');
                              case 'multiple':
                                    return esc_html__('Multiple <title> tags were found on page.', 'bug-monitor');
                              case 'too-long':
                                    return sprintf(esc_html__('<title> tag is too long. Maximum recommended length of <title> tag is 70 characters, on this page it is %d characters long: %s', 'bug-monitor'), (int)$event['details']['length'], esc_html($event['details']['text']));
                        }
                        return '';
                  case 'seo/description':
                        switch ($event['details']['issue']){
                              case 'missing':
                              case 'empty':
                                    return __('Meta description is missing.', 'bug-monitor');
                              case 'multiple':
                                    return __('Multiple meta description tags were found.', 'bug-monitor');
                              case 'too-short':
                                    return sprintf(__('Meta description is too short. Minimum recommended length of meta description is 120 characters, on this page it is %d characters long: %s%s%s', 'bug-monitor'), (int)$event['details']['length'], '<span class="bm-highlight">', esc_html($event['details']['text']), '</span>');
                              case 'too-long':
                                    return sprintf(__('Meta description is too long. Maximum recommended length of meta description is 160 characters, on this page it is %d characters long: %s%s%s', 'bug-monitor'), (int)$event['details']['length'], '<span class="bm-highlight">', substr(esc_html($event['details']['text']), 0, 100), '</span>');
                        }
                        return '';
                  case 'seo/image':
                        switch ($event['details']['issue']){
                              case 'missing-alt':
                                    $src = Bug_Monitor_Helper::truncate_str($event['details']['src']);
                                    return sprintf(__('ALT text is missing for image %s.', 'bug-monitor'), Bug_Monitor_Helper::get_link_tag($src));
                              case 'wrong-alt':
                                    $src = Bug_Monitor_Helper::truncate_str($event['details']['src']);
                                    return sprintf(__('It seems that the ALT text "%s" is not properly set for image: %s.', 'bug-monitor'), esc_html($event['details']['alt']), Bug_Monitor_Helper::get_link_tag($src));
                        }
                        return '';
                  case 'ux/non_responsive_element':
                        return __('An unclickable element on your page is attracting clicks from visitors. This can cause frustration and confusion for users who expect it to be interactive.', 'bug-monitor');
                  case 'ux/slow_response':
                        $response_time = '';
                        if (isset($event['duration'])){
                              if ($event['duration']['min'] == $event['duration']['max']){
                                    $response_time = sprintf(__('Response time is %dms'), (int)$event['duration']['min']);
                              }
                              else {
                                    $response_time = sprintf(__('Response time varies between %dms and %dms'), (int)$event['duration']['min'], (int)$event['duration']['max']);
                              }
                        }
                        switch ($event['details']['request_type']){
                              case 'AJAX':
                                    return sprintf(__('There is a slow AJAX request: %s. ', 'bug-monitor'), esc_html($event['details']['url'])) . $response_time;
                              case 'TTFB':
                                    return __('Navigation is slow. ', 'bug-monitor') . $response_time;
                        }
                        return '';
                  case 'ux/bounce':
                        return sprintf(__('Bounce rate is high (%s)', 'bug-monitor'), esc_html($event['details']['rate']));
                  case 'ui/too_close_clickable':
                        return __('Clickable elements too close together.', 'bug-monitor');
                  case 'ui/hard_read_text':
                        return __('The text is too small to be read easily. This issue makes reading on a mobile device difficult. View the test screenshot for your device to help identify the text that is hard to read.', 'bug-monitor');
                  case 'ui/layout':
                        return __('A layout issue has been detected on some devices.', 'bug-monitor');
                  case 'ui/content_obstruction':
                        return __('A content obstruction issue has been detected on some devices.', 'bug-monitor');
                  case 'ui/font':
                        // TODO
                        return '';
                  case 'js/error':
                        return __('A JavaScript error has been detected.', 'bug-monitor');
                  case 'webvitals/fcp':
                        return __('High First Contentful Paint (FCP) detected. This could lead to a delay in page load time, potentially dissuading users from waiting for the content to load.', 'bug-monitor');
                  case 'webvitals/lcp':
                        return __('High Largest Contentful Paint (LCP) detected. This can cause a significant delay in rendering the main content of the page, affecting user satisfaction and engagement. ', 'bug-monitor');
                  case 'webvitals/cls':
                        return __('High Cumulative Layout Shift (CLS) detected. This could create a visually unstable page layout, leading to a poor user experience.', 'bug-monitor');
                  case 'functional/non_responsive_button':
                        return __('There is a link or button on page, but nothing happened, when it has been clicked. Ensure it is functioning as intended to improve user experience.', 'bug-monitor');
                  case 'functional/form_submission':
                        return __('There appears to be an issue with a form on your site. It has been submitted by users, but it seems the submissions are not being recorded. Please check the form\'s functionality to ensure that submissions are being processed correctly.', 'bug-monitor');
                  case 'functional/form_abandonment':
                        return __('There appears to be an issue with a form on your site. It seems users start filling out a form but cannot submit it for some reason and leaves the site. Please check the form\'s functionality to ensure that submissions are being processed correctly.', 'bug-monitor');
                  case 'functional/broken_link':
                        return __('A link on your site is pointing to a page that does not exist. This may frustrate visitors and lead to a poor user experience. Please review and update the broken link to ensure it directs to the intended page.', 'bug-monitor');
                  case 'php/error':
                        return sprintf(__('A PHP error was caused by a %s', 'bug-monitor'), $event['details']['component']);
                  case 'php/warning':
                        return sprintf(__('A PHP warning was caused by a %s', 'bug-monitor'), $event['details']['component']);
                  case 'php/redirect_loop':
                        return __('Redirect loop detected', 'bug-monitor');
                  case 'php/malicious_redirect':
                        return __('Suspicious redirect has been detected.', 'bug-monitor');
                  case 'php/email_sending_error':
                        return __('An error occurred while sending an email.', 'bug-monitor');

                  default:
                  return json_encode($event['details']);
            }
      }

      public static function load_event(){
            $logs = Bug_Monitor_Log::get_logs(array('event_hash' => $_POST['id']));
            echo Bug_Monitor_Helper::get_template('details', array_pop($logs));
      }
      public static function ai_help($event_hash){
            $logs = Bug_Monitor_Log::get_logs(array('event_hash' => $event_hash));
            $event = array_pop($logs);

            if (empty($event)){
                  wp_send_json(array('success' => false, 'message' => __('This event has already been solved or deleted.', 'bug-monitor')));
            }

            $details = (!empty($event['details']) && is_array($event['details']) ? $event['details'] : array());

            unset($details['selector'], $details['target']);

            $visual = (!empty($event['visual_type']) ? $event['visual_type'] : 'none');

            $payload = array(
                  'type'             => $event['type'],
                  'level'            => $event['level'],
                  'title'            => self::get_title($event['type']),
                  'description'      => trim(wp_strip_all_tags(self::get_description($event))),
                  'details'          => $details,
                  'visual'           => $visual, // image | video | email | none
                  'has_live_preview' => !empty($event['preview_link']),
                  'files'            => self::collect_source_files($details),
            );

            $res = Bug_Monitor_API::request('ai-help', array('payload' => wp_json_encode($payload)));

            if (empty($res)){
                  wp_send_json(array('success' => false, 'message' => __('Could not reach the AI service. Please try again later.', 'bug-monitor')));
            }

            $body = json_decode($res['body'], true);

            if (empty($body) || empty($body['success']) || empty($body['answer'])){
                  $message = (!empty($body['message']) ? $body['message'] : __('The AI service returned an error.', 'bug-monitor'));
                  wp_send_json(array('success' => false, 'message' => $message));
            }

            wp_send_json(array('success' => true, 'answer' => $body['answer']));
      }
      private static function collect_source_files($details){
            $files = array();
            $candidates = array();
            if (!empty($details['file'])){
                  $candidates[] = $details['file'];
            }

            $error_line = (!empty($details['line']) ? (int)$details['line'] : 0);

            foreach (array_unique($candidates) as $path){
                  $excerpt = self::read_source_excerpt($path, $error_line);
                  if ($excerpt !== null){
                        $files[] = $excerpt;
                  }
                  if (count($files) >= 3){
                        break;
                  }
            }

            return $files;
      }
      private static function read_source_excerpt($path, $line = 0, $context = 60, $max_bytes = 16000){
            $path    = wp_normalize_path($path);
            $abspath = wp_normalize_path(ABSPATH);
            if (strpos($path, $abspath) !== 0 || !is_file($path) || !is_readable($path)){
                  return null;
            }

            $lines = @file($path, FILE_IGNORE_NEW_LINES);
            if ($lines === false){
                  return null;
            }

            $total = count($lines);
            if ($line > 0 && $total > 2 * $context){
                  $start = max(0, $line - $context - 1);
                  $end   = min($total, $line + $context);
                  $slice = array_slice($lines, $start, $end - $start);
                  $numbered = array();
                  foreach ($slice as $i => $text){
                        $numbered[] = ($start + $i + 1) . ': ' . $text;
                  }
                  $content = implode("\n", $numbered);
            }
            else {
                  $numbered = array();
                  foreach ($lines as $i => $text){
                        $numbered[] = ($i + 1) . ': ' . $text;
                  }
                  $content = implode("\n", $numbered);
            }

            if (strlen($content) > $max_bytes){
                  $content = substr($content, 0, $max_bytes) . "\n… (truncated)";
            }

            return array(
                  'path'       => str_replace($abspath, '', $path),
                  'error_line' => (int)$line,
                  'content'    => $content,
            );
      }

      public static function session_endpoint(){
            if (isset($_GET['bm-session'])){
                  if (!current_user_can('manage_options')){
                        wp_die(esc_html__('You are not allowed to view this session.', 'bug-monitor'), '', array('response' => 403));
                  }

                  echo Bug_Monitor_Helper::get_template('session');
                  die;
            }
      }
      public static function toolbar($admin_bar){
            if (current_user_can('manage_options') && Bug_Monitor::check_option('system/disable_toolbar', 'on', '!=')){
                  $admin_bar->add_menu(array(
                        'id'    => 'bug-monitor',
                        'href'  => Bug_Monitor_Helper::get_dashbord_url(),
                        'title' => Bug_Monitor_Helper::get_template('toolbar')
                  ));
            }
      }

      public static function format_js_error($data){
            $message = esc_html($data['details']['message']);
            $stack = esc_html((string)$data['details']['stack']);
            $lines = explode("\n", $stack);
            array_unshift($lines, "<span class=\"bm-js-error\">" . $message . "</span>");
            $stack = implode("\n", $lines);
            $stack = preg_replace(
                '~\bhttps?:\/\/[^\s]+?(?=\s|$|:\d+(:\d+)?)~',
                '<a href="$0" target="_blank">$0</a>',
                $stack
            );

            return $stack;
      }

      public static function i18n(){
            return array(
                  'No endpoints have been set up yet.' => __('No endpoints have been set up yet.', 'bug-monitor'),
                  'Analyzing the error…' => __('Analyzing the error…', 'bug-monitor'),
                  'Something went wrong. Please try again.' => __('Something went wrong. Please try again.', 'bug-monitor'),
                  'Request failed. Please try again.' => __('Request failed. Please try again.', 'bug-monitor'),
                  'Likely a false positive' => __('Likely a false positive', 'bug-monitor'),
                  'What happened' => __('What happened', 'bug-monitor'),
                  'How to fix it' => __('How to fix it', 'bug-monitor'),
                  'Technical details' => __('Technical details', 'bug-monitor'),
                  'Learn more' => __('Learn more', 'bug-monitor'),
            );
      }

      public static function show_notices(){
            if (current_user_can('manage_options')){
                  $notices = Bug_Monitor::get_option('notices', array());
                  if (!empty($notices)){
                        foreach ($notices as $id => $message) {
                              echo Bug_Monitor_Helper::get_template('admin-notice', array('id' => $id, 'message' => $message));
                        }
                        wp_enqueue_script('bug-monitor-notice', BUG_MONITOR_PLUGIN_URL . 'assets/admin-notice.js');
                  }
            }
      }

      public static function add_notice($message, $id = false){
            $id = (empty($id) ? md5($message) : md5($id));
            $notices = Bug_Monitor::get_option('notices', array());
            $notices[$id] = $message;
            Bug_Monitor::update_option('notices', $notices);
      }

      public static function delete_notice($id){
            $notices = Bug_Monitor::get_option('notices', array());
            unset($notices[$id]);
            Bug_Monitor::update_option('notices', $notices);
      }

}