<?php
/**
 * Class VOIDEMPO_Includes
 *
 * Handles inclusion of core functionality and sets up required hooks
 * for the frontend dashboard plugin or system.
 *
 * This class may include route registration, template loading,
 * user access control, and other common setup tasks.
 *
 * @package voidempo
 */
class VOIDEMPO_Includes {
	/**
	 * Class constructor.
	 *
	 * Initializes the class by setting up hooks, actions, or loading dependencies.
	 * This is typically used to register WordPress hooks and filters during instantiation.
	 */
	public function __construct() {
		add_action( 'template_redirect', array( $this, 'voidempo_redirect_non_admin_users' ) );
		add_action( 'admin_init', array( $this, 'voidempo_restrict_admin_access' ) );
		add_action( 'after_setup_theme', array( $this, 'voidempo_hide_admin_bar_for_non_admins' ) );
		add_filter( 'the_title', array( $this, 'voidempo_hide_page_title' ), 10, 2 );
		add_filter( 'template_include', array( $this, 'voidempo_load_custom_template' ) );

		// AJAX actions for dynamic content loading.
		add_action( 'wp_ajax_voidempo_load_dashboard_content', array( $this, 'voidempo_load_dashboard_content' ) );

		add_action( 'wp_ajax_voidempo_filtertableeodlist', array( $this, 'voidempo_filtertableeodlist' ) );

		add_action( 'wp_ajax_voidempo_filterprojectlist', array( $this, 'voidempo_filterprojectlist' ) );

		add_action( 'wp_ajax_voidempo_func_export_to_excel3', array( $this, 'voidempo_func_export_to_excel3' ) );

		add_action( 'template_redirect', array( $this, 'voidempo_force_dashboard_redirect' ) );
		add_action( 'wp_login', array( $this, 'voidempo_custom_login_redirect' ), 10, 2 );

		add_action( 'wp_ajax_voidempo_filtertasklist', array( $this, 'voidempo_filtertasklist' ) );

		add_action( 'wp_ajax_voidempo_filtereodsummary', array( $this, 'voidempo_filtereodsummary' ) );

		add_action( 'wp_ajax_voidempo_filtertablereportlist', array( $this, 'voidempo_filtertablereportlist' ) );

		add_action( 'wp_ajax_voidempo_func_export_to_excel2', array( $this, 'voidempo_func_export_to_excel2' ) );

		add_action( 'wp_ajax_voidempo_missing_eod_data', array( $this, 'voidempo_missing_eod_data' ) );

	}

	/**
	 * Redirects non-admin users to a custom frontend dashboard after login.
	 *
	 * This function checks the user's role and redirects them to a custom page
	 * if they are not an administrator. Useful for customizing the login experience
	 * in member or employee portals.
	 *
	 * @return void Performs a redirect for non-admin users.
	 */
	public function voidempo_redirect_non_admin_users() {
		if ( ! is_user_logged_in() || wp_doing_ajax() ) {
			return;
		}

		if ( current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( current_user_can( 'manage_options' ) ) {
			wp_safe_redirect( home_url( '/user-dashboard' ) );
			exit;
		}
	}

	/**
	 * Restricts access to the WordPress admin area for non-admin users.
	 *
	 * This function prevents users without the 'administrator' capability
	 * from accessing the wp-admin area directly. It can be used to enforce
	 * frontend-only access for roles like subscribers, employees, or managers.
	 *
	 * @return void Redirects unauthorized users to the homepage or a custom URL.
	 */
	public function voidempo_restrict_admin_access() {
		if ( current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( ! current_user_can( 'manage_options' ) && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
			wp_safe_redirect( home_url( '/user-dashboard' ) );
			exit;
		}
	}

	/**
	 * Hides the WordPress admin bar for non-admin users on the frontend.
	 *
	 * This function disables the admin bar for all users except administrators.
	 * Useful for frontend dashboards or custom user experiences.
	 *
	 * @return void
	 */
	public function voidempo_hide_admin_bar_for_non_admins() {
		if ( ! current_user_can( 'manage_options' ) ) {
			add_filter( 'show_admin_bar', '__return_false' );
		}
	}


	/**
	 * Filters the page title to hide it on specific pages.
	 *
	 * This function is typically used to return an empty title for specific pages
	 * (like a frontend dashboard) where the default title display should be suppressed.
	 *
	 * @param string $title The current page title.
	 * @param int    $id    The ID of the current post or page.
	 *
	 * @return string The modified title (possibly empty).
	 */
	public function voidempo_hide_page_title( $title, $id ) {
		if ( is_page( 'user-dashboard' ) ) {
			return '';
		}
		return $title;
	}

	/**
	 * Loads a custom template for the frontend dashboard or specific pages.
	 *
	 * This method filters the default page template and replaces it with a
	 * custom template file based on certain conditions, such as specific page
	 * slugs or user roles.
	 *
	 * @param string $template The path to the template to be included.
	 *
	 * @return string The path to the custom template, if applicable.
	 */
	public function voidempo_load_custom_template( $template ) {

		if ( is_page( 'user-dashboard' ) ) {
			return VOIDEMPO_PLUGIN_PATH . 'templates/user-dashboard.php';
		}
		return $template;
	}

	/**
	 * Redirects users to a custom dashboard after login based on their role.
	 *
	 * This function hooks into the login process and redirects users to a custom
	 * frontend dashboard page instead of the default WordPress admin area.
	 * Administrators can still access the admin dashboard.
	 *
	 * @param string  $user_login Username of the user logging in.
	 * @param WP_User $user       WP_User object of the logged-in user.
	 *
	 * @return void Performs a redirect based on user role.
	 */
	public function voidempo_custom_login_redirect( $user_login, $user ) {
		if (  ! current_user_can( 'manage_options' ) ) {
			wp_safe_redirect( home_url( '/user-dashboard' ) );
			exit;
		}
	}
	/**
	 * Forces non-admin users to redirect to the custom voidempo
	 *
	 * This function hooks into the login or page load process and redirects users
	 * (excluding administrators) to a specific dashboard page to limit backend access.
	 *
	 * @return void Performs a redirect if conditions are met.
	 */
	public function voidempo_force_dashboard_redirect() {
		if ( is_page( 102 ) &&  ! current_user_can( 'manage_options' ) ) {
			wp_safe_redirect( home_url( '/user-dashboard' ) );
			exit;
		}
	}

	/**
	 * Loads and returns dynamic content for the user dashboard.
	 *
	 * This method is typically used to load specific dashboard components
	 * via AJAX or based on user roles and permissions. It may include widgets,
	 * summaries, or user-specific data.
	 *
	 * @return void Outputs HTML or JSON content for the dashboard view.
	 */
	public function voidempo_load_dashboard_content() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );

		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}

		$default_menu = array(
			'dashboard'            => 'dashboard.php',
			'calendar_view'        => 'holiday.php',
			'add_projects'         => 'add-projects.php',
			'projects'             => 'project-lists.php',
			'voidempo_eod'         => 'create-eod.php',
			'eod_list'             => 'projects-eod-view.php',
			'view-task'            => 'projects-view-task.php',
			'leave'                => 'apply-leave.php',
			'voidempo_create_task' => 'create-task.php',
			'task_summary'         => 'report.php',
			'eod_summary'          => 'eod-summary.php',
			'users'                => 'add-users.php',
		);

		$dashboard_menu = apply_filters( 'voidempo_dashboard_menu', $default_menu );

		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
			$page = isset( $_POST['page'] ) ? sanitize_text_field( wp_unslash( $_POST['page'] ) ) : 'dashboard';
		} else {
			$page = get_query_var( 'custom_page', 'dashboard' );
		}

		if ( ! array_key_exists( $page, $dashboard_menu ) ) {
			$message = array( 'message' => 'Invalid Page' );
			if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
				wp_send_json_error( $message );
			} else {
				wp_die( esc_html( $message['message'] ) );
			}
		}

		$default_template_path = VOIDEMPO_PLUGIN_PATH . 'templates/' . $dashboard_menu[ $page ];
		$template_path         = apply_filters( 'voidempo_template_path_override', $default_template_path, $dashboard_menu[ $page ] );

		if ( ! file_exists( $template_path ) ) {
			$message = array( 'message' => 'Template not found: ' . $template_path );
			if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
				wp_send_json_error( $message );
			} else {
				wp_die( esc_html( $message['message'] ) );
			}
		}

		ob_start();
		include $template_path;

		$output = ob_get_clean();

		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
			wp_send_json_success(
				array(
					'html' => $output,
				)
			);
		} else {
			echo wp_kses_post( $output );
		}

		wp_die();
	}


	/**
	 * Filters and returns a list of EOD (End of Day) reports in tabular format.
	 *
	 * This method is typically triggered via AJAX to display filtered EOD data
	 * based on parameters such as user ID, date range, or project.
	 *
	 * @return void Outputs a JSON response with the filtered EOD report data.
	 */
	public function voidempo_filtertableeodlist() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );

		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}
		global $wpdb;

		$columns_raw = filter_input( INPUT_POST, 'columns', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_REQUIRE_ARRAY );
		$columns     = array();

		if ( is_array( $columns_raw ) ) {
			$columns_raw = wp_unslash( $columns_raw );

			foreach ( $columns_raw as $key => $col ) {
				$sanitized_col           = array();
				$sanitized_col['data']   = isset( $col['data'] ) ? sanitize_key( $col['data'] ) : '';
				$sanitized_col['name']   = isset( $col['name'] ) ? sanitize_text_field( $col['name'] ) : '';
				$sanitized_col['search'] = array(
					'value' => isset( $col['search']['value'] ) ? sanitize_text_field( $col['search']['value'] ) : '',
					'regex' => isset( $col['search']['regex'] ) ? sanitize_text_field( $col['search']['regex'] ) : 'false',
				);

				$columns[ $key ] = $sanitized_col;
			}
		}

		$order = filter_input( INPUT_POST, 'order', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_REQUIRE_ARRAY );
		$o     = 'ORDER BY e.date_created DESC';

		if (
			is_array( $order )
			&& isset( $order[0]['column'], $order[0]['dir'] )
		) {
			$col_index = absint( $order[0]['column'] );
			$dir_raw   = sanitize_text_field( $order[0]['dir'] );
			$dir       = in_array( strtolower( $dir_raw ), array( 'asc', 'desc' ), true ) ? $dir_raw : 'desc';

			switch ( $col_index ) {
				case 0:
					$o = "ORDER BY p.project_title $dir";
					break;
				case 1:
					$o = "ORDER BY t.task_title $dir";
					break;
				case 2:
					$o = "ORDER BY t.task_description $dir";
					break;
				case 3:
					$o = "ORDER BY u.display_name $dir";
					break;
				case 4:
					$o = "ORDER BY TIME_TO_SEC(e.hours) $dir";
					break;
				case 5:
					$o = "ORDER BY e.status $dir";
					break;
				case 6:
					$o = "ORDER BY e.notes $dir";
					break;
				default:
					$o = 'ORDER BY e.date_created DESC';
					break;
			}
		}

		/**
		 * WHERE conditions
		 */
		$where_clauses = array( 'e.is_delete != %d' );
		$params        = array( 1 ); // for e.is_delete != 1

		if ( ! empty( $_POST['from_date'] ) ) {
			$where_clauses[] = 'e.date_created >= %s';
			$params[]        = sanitize_text_field( wp_unslash( $_POST['from_date'] ) );
		}

		if ( ! empty( $_POST['to_date'] ) ) {
			$where_clauses[] = 'e.date_created <= %s';
			$params[]        = sanitize_text_field( wp_unslash( $_POST['to_date'] ) );
		}

		if ( ! empty( $_POST['project_filter'] ) && $_POST['project_filter'] != '0' ) {
			$where_clauses[] = 'p.related_post_id = %d';
			$params[]        = absint( $_POST['project_filter'] );
		}

		if ( ! empty( $_POST['task_filter'] ) && $_POST['task_filter'] != '0' ) {
			$where_clauses[] = 't.task_title = %s';
			$params[]        = sanitize_text_field( wp_unslash( $_POST['task_filter'] ) );
		}

		// Per-column searches
		if ( ! empty( $columns[1]['search']['value'] ) ) {
			$val             = '%' . $wpdb->esc_like( $columns[1]['search']['value'] ) . '%';
			$where_clauses[] = '(t.task_title LIKE %s OR e.date_created LIKE %s)';
			$params[]        = $val;
			$params[]        = $val;
		}
		if ( ! empty( $columns[2]['search']['value'] ) ) {
			$val             = '%' . $wpdb->esc_like( $columns[2]['search']['value'] ) . '%';
			$where_clauses[] = 't.task_description LIKE %s';
			$params[]        = $val;
		}
		if ( ! empty( $columns[3]['search']['value'] ) ) {
			$val             = '%' . $wpdb->esc_like( $columns[3]['search']['value'] ) . '%';
			$where_clauses[] = 'u.display_name LIKE %s';
			$params[]        = $val;
		}
		if ( ! empty( $columns[4]['search']['value'] ) ) {
			$val             = '%' . $wpdb->esc_like( $columns[4]['search']['value'] ) . '%';
			$where_clauses[] = 'e.hours LIKE %s';
			$params[]        = $val;
		}
		if ( ! empty( $columns[5]['search']['value'] ) ) {
			$val             = '%' . $wpdb->esc_like( $columns[5]['search']['value'] ) . '%';
			$where_clauses[] = 'e.status LIKE %s';
			$params[]        = $val;
		}
		if ( ! empty( $columns[6]['search']['value'] ) ) {
			$val             = '%' . $wpdb->esc_like( $columns[6]['search']['value'] ) . '%';
			$where_clauses[] = 'e.notes LIKE %s';
			$params[]        = $val;
		}

		$where_sql = 'WHERE ' . implode( ' AND ', $where_clauses );

		// Pagination.
		$start  = isset( $_POST['start'] ) ? intval( $_POST['start'] ) : 0;
		$length = isset( $_POST['length'] ) ? intval( $_POST['length'] ) : 10;

		if ( current_user_can('voidempo_manager_access') || current_user_can( 'manage_options' ) ) {

			// --- Caching keys based on params ---.
			$cache_key      = 'voidempo_all_todays_eod_' . md5( serialize( array( $params, $o, $start, $length ) ) );
			$all_todays_eod = wp_cache_get( $cache_key, 'voidempo_eod' );

			if ( false === $all_todays_eod ) {

				$data_params = array_merge( $params, array( $length, $start ) );

				$all_todays_eod = $wpdb->get_results(
					$wpdb->prepare(
						"
					SELECT 
						e.id, e.date_created, e.hours, e.notes, e.status AS eod_status,
						u.display_name,
						t.task_title, t.task_description, t.status AS task_status, 
						t.estimated_hours, t.members_status AS members_task_status, t.user_id AS task_members,
						p.project_title, p.status AS project_status,
						(SELECT display_name FROM {$wpdb->prefix}users WHERE ID = p.manager_id) AS managername
					FROM {$wpdb->prefix}voidempo_eod AS e
					INNER JOIN {$wpdb->prefix}voidempo_task AS t ON e.task_id = t.id
					INNER JOIN {$wpdb->prefix}voidempo_projects AS p ON e.project_id = p.related_post_id
					INNER JOIN {$wpdb->prefix}users AS u ON u.ID = e.user_id
					{$where_sql}
					{$o}
					LIMIT %d OFFSET %d
				",
						...$data_params
					)
				);

				wp_cache_set( $cache_key, $all_todays_eod, 'voidempo_eod', 600 );
			}

			// --- Count query ---
			$cache_key_cnt     = 'voidempo_all_todays_eodcnt_' . md5( serialize( array( $params, $o ) ) );
			$all_todays_eodcnt = wp_cache_get( $cache_key_cnt, 'voidempo_eod' );

			if ( false === $all_todays_eodcnt ) {

				$all_todays_eodcnt = $wpdb->get_var(
					$wpdb->prepare(
						"
					SELECT COUNT(*)
					FROM {$wpdb->prefix}voidempo_eod AS e
					INNER JOIN {$wpdb->prefix}voidempo_task AS t ON e.task_id = t.id
					INNER JOIN {$wpdb->prefix}voidempo_projects AS p ON e.project_id = p.related_post_id
					INNER JOIN {$wpdb->prefix}users AS u ON u.ID = e.user_id
					{$where_sql}
				",
						...$params
					)
				);

				wp_cache_set( $cache_key_cnt, $all_todays_eodcnt, 'voidempo_eod', 600 );
			}
		} else {
			$current_user_id = get_current_user_id();
			$start           = isset( $_POST['start'] ) ? intval( $_POST['start'] ) : 0;
			$length          = isset( $_POST['length'] ) ? intval( $_POST['length'] ) : 10;
			$cache_key       = 'voidempo_all_todays_eod_' . md5( $current_user_id . $q . $o . $start . $length );
			$all_todays_eod  = wp_cache_get( $cache_key, 'voidempo_eod' );
			if ( false === $all_todays_eod ) {
				$all_todays_eod = $wpdb->get_results(
					$wpdb->prepare(
						"
							SELECT 
								e.*, 
								u.display_name, 
								t.manager_id, 
								t.task_title, 
								t.task_description, 
								p.status AS project_status, 
								t.status, 
								t.estimated_hours, 
								t.members_status AS members_task_status, 
								t.user_id AS task_members, 
								p.project_title, 
								e.status AS eod_status, 
								(SELECT display_name FROM {$wpdb->prefix}users WHERE ID = p.manager_id) AS managername 
							FROM 
								{$wpdb->prefix}voidempo_task AS t, 
								{$wpdb->prefix}voidempo_eod AS e, 
								{$wpdb->prefix}voidempo_projects AS p, 
								{$wpdb->prefix}users AS u 
							WHERE 
								u.ID = e.user_id 
								AND e.task_id = t.id 
								AND (
									CASE 
										WHEN t.manager_id = %d THEN t.manager_id = %d 
										ELSE e.user_id = %d 
									END
								) 
								AND e.project_id = p.related_post_id 
								AND e.is_delete != '1' 
								$q $o
							LIMIT %d, %d
							",
						$current_user_id,
						$current_user_id,
						$current_user_id,
						$start,
						$length
					)
				);
				wp_cache_set( $cache_key, $all_todays_eod, 'voidempo_eod', 600 );
			}
			$current_user_id = get_current_user_id();
			$q               = '';
			if ( ! empty( $where_clauses ) ) {
				$q = ' AND ' . implode( ' AND ', $where_clauses );
			}

			// Cache key for result
			$cache_key      = 'voidempo_all_todays_eod_' . md5( $current_user_id . $q . $o . $start . $length );
			$all_todays_eod = wp_cache_get( $cache_key, 'voidempo_eod' );

			if ( false === $all_todays_eod ) {
				$data_params = array_merge( array( $current_user_id, $current_user_id, $current_user_id ), $params, array( $length, $start ) );

				$all_todays_eod = $wpdb->get_results(
					$wpdb->prepare(
						"
						SELECT 
							e.*, 
							u.display_name, 
							t.manager_id, 
							t.task_title, 
							t.task_description, 
							p.status AS project_status, 
							t.status, 
							t.estimated_hours, 
							t.members_status AS members_task_status, 
							t.user_id AS task_members, 
							p.project_title, 
							e.status AS eod_status, 
							(SELECT display_name FROM {$wpdb->prefix}users WHERE ID = p.manager_id) AS managername 
						FROM 
							{$wpdb->prefix}voidempo_task AS t, 
							{$wpdb->prefix}voidempo_eod AS e, 
							{$wpdb->prefix}voidempo_projects AS p, 
							{$wpdb->prefix}users AS u 
						WHERE 
							u.ID = e.user_id 
							AND e.task_id = t.id 
							AND (
								CASE 
									WHEN t.manager_id = %d THEN t.manager_id = %d 
									ELSE e.user_id = %d 
								END
							) 
							AND e.project_id = p.related_post_id 
							AND e.is_delete != '1' 
							$q $o
						LIMIT %d OFFSET %d
						",
						...$data_params
					)
				);

				wp_cache_set( $cache_key, $all_todays_eod, 'voidempo_eod', 600 );
			}

			// Cache key for count
			$cache_key_cnt     = 'voidempo_all_todays_eodcnt_' . md5( $current_user_id . $q . $o );
			$all_todays_eodcnt = wp_cache_get( $cache_key_cnt, 'voidempo_eod' );

			if ( false === $all_todays_eodcnt ) {
				$data_params = array_merge( array( $current_user_id, $current_user_id, $current_user_id ), $params );

				$all_todays_eodcnt = $wpdb->get_var(
					$wpdb->prepare(
						"
						SELECT COUNT(*)
						FROM 
							{$wpdb->prefix}voidempo_task AS t, 
							{$wpdb->prefix}voidempo_eod AS e, 
							{$wpdb->prefix}voidempo_projects AS p, 
							{$wpdb->prefix}users AS u 
						WHERE 
							u.ID = e.user_id 
							AND e.task_id = t.id 
							AND (
								CASE 
									WHEN t.manager_id = %d THEN t.manager_id = %d
									ELSE e.user_id = %d
								END
							) 
							AND e.project_id = p.related_post_id 
							AND e.is_delete != '1' 
							$q
						",
						...$data_params
					)
				);

				wp_cache_set( $cache_key_cnt, $all_todays_eodcnt, 'voidempo_eod', 600 );
			}
		}
		$jsonarr                    = array();
		$jsonarr['draw']            = isset( $_POST['draw'] ) ? sanitize_text_field( wp_unslash( $_POST['draw'] ) ) : 0;
		$jsonarr['recordsTotal']    = intval( $all_todays_eodcnt );
		$jsonarr['recordsFiltered'] = intval( $all_todays_eodcnt );
		$jsonarr['data']            = array();
		foreach ( $all_todays_eod as $all_todays_eod_data ) {

			$project_id = $all_todays_eod_data->project_id;

			$managername    = $all_todays_eod_data->managername;
			$project_status = $all_todays_eod_data->project_status;
			$project_title  = $all_todays_eod_data->project_title . '<hr>' . $project_status . '<hr>' . $managername;
			$members_id     = explode( ',', $all_todays_eod_data->task_members );
			$members_status = explode( ',', $all_todays_eod_data->members_task_status );
			$date_created   = $all_todays_eod_data->date_created;

			$task_ids         = $all_todays_eod_data->task_id;
			$task_title       = $all_todays_eod_data->task_title . '<hr>' . $date_created;
			$task_description = $all_todays_eod_data->task_description;

			if ( $all_todays_eod_data->status == 'Pending' ) {
				$bstrapbtnclass = 'btn btn-warning';
			}
			if ( $all_todays_eod_data->status == 'Completed' ) {
				$bstrapbtnclass = 'btn btn-success';
			}
			if ( $all_todays_eod_data->status == 'Inprogress' ) {
				$bstrapbtnclass = 'btn btn-primary';
			}
			if ( $all_todays_eod_data->status == 'Cancelled' ) {
				$bstrapbtnclass = 'btn btn-danger';
			}

			$user_names = $all_todays_eod_data->display_name;
			$xphr       = explode( ':', $all_todays_eod_data->hours )[0];
			$add_frnt   = '';
			if ( $xphr == 0 ) {
				$add_frnt = 0;
			}
			$hours = $add_frnt . ltrim( $all_todays_eod_data->hours, '0' );

			$notes  = $all_todays_eod_data->notes;
			$cutoff = '';
			$words  = array_filter( explode( ' ', $task_description ) );
			$words  = array_values( $words );

			if ( ! empty( $words ) ) {
				if ( strlen( $words[0] ) > 60 ) {
					$cutoff = substr( $words[0], 0, 60 );
				} else {
					$cutoff = array_shift( $words );
					while ( ! empty( $words ) && strlen( $cutoff . ' ' . $words[0] ) <= 60 ) {
						$cutoff .= ' ' . array_shift( $words );
					}
				}
			}

			if ( strlen( trim( $task_description ) ) >= 60 ) {
				$cutoff .= '...';
			}
			$task_description = '<div class="trrepdesc" data-id="' . $all_todays_eod_data->id . '"><div class="divshortdes' . $all_todays_eod_data->id . '">' . $cutoff . '</div>
					<div class="divlongdes' . $all_todays_eod_data->id . '" style="display:none;">' . $task_description . '</div></div>';

			$data_ar = array( $project_title, $task_title, $task_description, $user_names, $hours, $all_todays_eod_data->eod_status, esc_html( stripslashes( $notes ) ) );
			if ( current_user_can( 'manage_options' )|| current_user_can( 'voidempo_manager_access' ) ) {
				$action = '<button class="btn btn-danger voidempo_delete_eod_but" data-eod_id="' . $all_todays_eod_data->id . '" data-user_id="' . $all_todays_eod_data->user_id . '" data-project_id="' . $project_id . '" data-task_id="' . $task_ids . '" >Delete</button>
			<button class="btn btn-primary voidempo_update_eod_but" data-eod_id="' . $all_todays_eod_data->id . '" data-user_id="' . $all_todays_eod_data->user_id . '" data-project_id="' . $project_id . '" data-task_id="' . $task_ids . '">Update</button>';
				array_push( $data_ar, $action );
			}

			$jsonarr['data'][] = $data_ar;
		}
		echo wp_json_encode( $jsonarr );
		wp_die();
	}

	/**
	 * Filters and retrieves a list of projects based on given criteria.
	 *
	 * Typically triggered via an AJAX request. This method filters projects
	 * by parameters such as project status, assigned users, managers, or date range.
	 *
	 * @return void Outputs a JSON response with the filtered project list.
	 */
	public function voidempo_filterprojectlist() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}
		global $wpdb;

		$current_uid      = get_current_user_id();
		$searchablevalues = '';

		if ( isset( $_POST['search']['value'] ) ) {
			$searchablevalues = strtolower( trim( sanitize_text_field( wp_unslash( $_POST['search']['value'] ) ) ) );
		}
		$o             = '';
		$order_columns = array(
			0 => 'vp.project_title',
			1 => 'GROUP_CONCAT(DISTINCT u.display_name order by u.display_name asc)',
			2 => '(select display_name from ' . $wpdb->prefix . 'users where vp.manager_id = ID)',
			3 => 'vp.status',
			4 => 'vp.start_date',
			5 => 'vp.end_date',
		);

		$order_column_index = isset( $_POST['order'][0]['column'] )
			? absint( wp_unslash( $_POST['order'][0]['column'] ) )
			: 0;

		$order_direction_raw = isset( $_POST['order'][0]['dir'] )
			? sanitize_text_field( wp_unslash( $_POST['order'][0]['dir'] ) )
			: '';

		$order_direction = in_array( strtoupper( $order_direction_raw ), array( 'ASC', 'DESC' ), true )
			? strtoupper( $order_direction_raw )
			: 'ASC';

		if ( array_key_exists( $order_column_index, $order_columns ) ) {
			$o = 'ORDER BY ' . $order_columns[ $order_column_index ] . ' ' . $order_direction;
		} else {
			$o = 'ORDER BY vp.project_title ASC';
		}

		if ( current_user_can ( 'manage_options' )|| current_user_can ( 'voidempo_manager_access' ) ) {
			$cache_key   = 'voidempo_my_projects_list_' . md5( $o );
			$my_projects = wp_cache_get( $cache_key, 'voidempo_projects' );

			if ( false === $my_projects ) {
				$my_projects = $wpdb->get_results(
					$wpdb->prepare(
						"
						SELECT 
							vp.*, 
							GROUP_CONCAT(DISTINCT u.display_name ORDER BY u.display_name ASC) AS members,
							(
								SELECT display_name 
								FROM {$wpdb->prefix}users 
								WHERE vp.manager_id = ID
							) AS manager
						FROM {$wpdb->prefix}voidempo_projects AS vp
						INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = vp.related_post_id
						INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
						INNER JOIN {$wpdb->prefix}users AS u ON FIND_IN_SET(u.ID, vp.member_id) > 0
						WHERE 
							p.post_status = 'publish'
							AND p.post_type = 'voidempo_projects'
						GROUP BY vp.id
						$o
					"
					)
				);

				wp_cache_set( $cache_key, $my_projects, 'voidempo_projects', 600 );
			}
		} else {
			$cache_key   = 'my_projects_for_user_' . $current_uid;
			$my_projects = wp_cache_get( $cache_key, 'voidempo_projects' );

			if ( false === $my_projects ) {
				$my_projects = $wpdb->get_results(
					$wpdb->prepare(
						"
					SELECT 
						vp.*, 
						GROUP_CONCAT(DISTINCT u.display_name ORDER BY u.display_name ASC) AS members,
						(SELECT display_name FROM {$wpdb->prefix}users WHERE ID = vp.manager_id) AS manager
					FROM {$wpdb->prefix}voidempo_projects AS vp,
						{$wpdb->prefix}posts AS p,
						{$wpdb->prefix}postmeta AS pm,
						{$wpdb->prefix}users AS u
					WHERE 
						(
							FIND_IN_SET(%d, vp.member_id) 
							OR FIND_IN_SET(%d, vp.manager_id) <> 0
						)
						AND p.ID = vp.related_post_id
						AND p.post_status = 'publish'
						AND p.post_type = 'voidempo_projects'
						AND p.ID = pm.post_id
						AND FIND_IN_SET(u.ID, vp.member_id) > 0
					GROUP BY vp.id
					$o
					",
						$current_uid,
						$current_uid
					)
				);
				wp_cache_set( $cache_key, $my_projects, 'voidempo_projects', 600 );
			}
		}
		$jsonarr         = array();
		$jsonarr['draw'] = isset( $_POST['draw'] ) ? intval( $_POST['draw'] ) : 0;

		$i           = 0;
		$k           = 0;
		$pdata       = array();
		$start       = isset( $_POST['start'] ) ? intval( wp_unslash( $_POST['start'] ) ) : 0;
		$length      = isset( $_POST['length'] ) ? intval( wp_unslash( $_POST['length'] ) ) : 10;
		$totallength = 0;
		foreach ( $my_projects as $res ) {
			$project_title      = strtolower( $res->project_title );
			$members            = strtolower( $res->members );
			$manager            = strtolower( $res->manager );
			$project_status     = strtolower( str_replace( 'Pending', 'Inprogress', $res->status ) );
			$project_start_data = $res->start_date;
			if ( strtotime( $project_start_data ) == '19800' ) {
				$project_start_data = '';
			}
			$project_end_data = $res->end_date;
			if ( strtotime( $project_end_data ) == '19800' ) {
				$project_end_data = '';
			}

			if ( ! empty( $searchablevalues ) ) {
				if (
					strpos( $project_title, $searchablevalues ) !== false || strpos( $members, $searchablevalues )
					!== false || strpos( $manager, $searchablevalues ) !== false ||
					strpos( $project_status, $searchablevalues ) !== false ||
					strpos( $project_start_data, $searchablevalues ) !== false ||
					strpos( $project_end_data, $searchablevalues ) !== false
				) {
					if ( $i >= $start && $k < $length ) {
						$pdata[] = $res;
						++$k;
					}
					++$i;
					$totallength += 1;
				}
			}
			if (
				empty( $searchablevalues )
			) {
				if ( $i >= $start && $k < $length ) {
					$pdata[] = $res;
					++$k;
				}
				++$i;
				$totallength += 1;
			}
		}
		$jsonarr['recordsTotal']    = $totallength;
		$jsonarr['recordsFiltered'] = $totallength;
		if ( ! empty( $pdata ) ) {
			foreach ( $pdata as
				$my_projects_data ) {
				$pid                = $my_projects_data->related_post_id;
				$project_title      = $my_projects_data->project_title;
				$project_desc       = $my_projects_data->project_desc;
				$project_status     = $my_projects_data->status;
				$project_start_data = '<div class="text-center">' . $my_projects_data->start_date . '</div>';
				if ( strtotime( $project_start_data ) == '19800' ) {
					$project_start_data = '';
				}

				$project_end_data = '<div class="text-center">' . $my_projects_data->end_date . '</div>';

				if ( strtotime( $project_end_data ) == '19800' ) {
					$project_end_data = '';
				}
				$project_members = $my_projects_data->members;
				$project_manager = $my_projects_data->manager;

				if ( $project_status === 'Completed' ) {
					$btn_class = 'btn-success';
				}
				if ( $project_status === 'Pending' ) {
					$btn_class = 'btn-primary';
				}

				$cache_key = 'task_status_summary_' . $pid;
				$all_tasks = wp_cache_get( $cache_key, 'custom_tasks' );

				if ( false === $all_tasks ) {
					$all_tasks = $wpdb->get_results(
						$wpdb->prepare(
							"
						SELECT status, COUNT(*) AS countstatus, MAX(date_created) as latest_created
						FROM {$wpdb->prefix}voidempo_task
						WHERE project_id = %d AND is_delete = 0
						GROUP BY status
						ORDER BY latest_created DESC
						",
							$pid
						)
					);

					wp_cache_set( $cache_key, $all_tasks, 'custom_tasks', 600 );
				}

				$taskarray = array();
				foreach ( $all_tasks as $tasksmeta ) {
					$taskarray[ $tasksmeta->status ] = $tasksmeta->countstatus;
				}
				$status_countpen = 0;
				if ( ! empty( $taskarray['Pending'] ) ) {
					$status_countpen = $taskarray['Pending'];
				}
				$roundhousesinptatuscolor = '';
				$status_countinpro        = 0;
				if ( ! empty( $taskarray['Inprogress'] ) ) {
					$status_countinpro = $taskarray['Inprogress'];
				}
				$roundhousecomstatuscolor = '';
				$status_countcom          = 0;
				if ( ! empty( $taskarray['Completed'] ) ) {
					$status_countcom = $taskarray['Completed'];
				}

				$projecttitlehtml = '<div>' . $project_title . '<div class="roundhouse_project d-flex">
                                       <div
                                            style="background-color:#ffc107b8;border-color:#ffc107;display: flex;justify-content: center;
											border-radius: 30px;padding: 15px 20px;margin-left: 10px;">
                                            ' . $status_countpen . '</div>
                                        <div
                                            style="background-color:#007bffc4;border-color:#007bff;display: flex;justify-content: center;
											border-radius: 30px;padding: 15px 20px;margin-left: 10px;">
                                            ' . $status_countinpro . '</div>
                                        <div
                                            style="background-color:#28a745c7;border-color:#28a745;display: flex;justify-content: center;
											border-radius: 30px;padding: 15px 20px;margin-left: 10px;">
                                            ' . $status_countcom . '</div>
                                    </div>
                                </div>';
				$btnstatus        = '';
				$btnstatus       .= '<button disabled class="btn ' . $btn_class . '">';
				if ( $project_status == 'Pending' ) {
					$btnstatus .= 'Inprogress';
				} else {
					$btnstatus .=
						$project_status;
				}
				$btnstatus .= '</button>';

				$project_id   = esc_attr( $my_projects_data->related_post_id );
				$profile_link = site_url( 'user-dashboard/view-task/?project_id=' . $project_id );

				$action = '<a href="' . esc_url( $profile_link ) . '" class="btn btn-primary   view-task-btn" style="width: 100px;" data-project-id="' . esc_attr( $project_id ) . '">
					View Task
				</a>';

				$jsonarr['data'][] =
					array(
						$projecttitlehtml,
						$project_members,
						$project_manager,
						$btnstatus,
						$project_start_data,
						$project_end_data,
						$action,
					);

			}
		} else {
			$jsonarr['data'][] = array( '', '', '', '', '', '', '' );
		}

		echo wp_json_encode( $jsonarr );

		die();
	}

	/**
	 * Exports specific data to an Excel file.
	 *
	 * This function handles the export of filtered or structured data to an Excel-compatible
	 *
	 * @return void Outputs the Excel file to the browser and exits.
	 */
	public function voidempo_func_export_to_excel2() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}
		global $wpdb;

		$conditions = array();
		$params     = array();

		// Date filters
		if ( ! empty( $_POST['from_date'] ) ) {
			$conditions[] = 'e.date_created >= %s';
			$params[]     = sanitize_text_field( wp_unslash( $_POST['from_date'] ) );
		}
		if ( ! empty( $_POST['to_date'] ) ) {
			$conditions[] = 'e.date_created <= %s';
			$params[]     = sanitize_text_field( wp_unslash( $_POST['to_date'] ) );
		}

		// Project filter
		if ( ! empty( $_POST['project_filter'] ) && $_POST['project_filter'] != '0' ) {
			$conditions[] = 'p.related_post_id = %d';
			$params[]     = intval( $_POST['project_filter'] );
		}

		// Task filter
		if ( ! empty( $_POST['task_filter'] ) && $_POST['task_filter'] != '0' ) {
			$conditions[] = 't.task_title = %s';
			$params[]     = sanitize_text_field( wp_unslash( $_POST['task_filter'] ) );
		}

		// Role-based clause
		$current_user_id = get_current_user_id();
		if (  ! current_user_can( 'manage_options' ) && ! current_user_can( 'voidempo_manager_access' ) ) {
			$conditions[] = '( (t.manager_id = %d AND t.manager_id = %d) OR (t.manager_id != %d AND e.user_id = %d) )';
			$params[]     = $current_user_id;
			$params[]     = $current_user_id;
			$params[]     = $current_user_id;
			$params[]     = $current_user_id;
		}

		// Combine conditions
		$where_clause = '';
		if ( ! empty( $conditions ) ) {
			$where_clause = ' AND ' . implode( ' AND ', $conditions );
		}

			// Cache key
			$cache_key   = md5( 'eod_task_query_' . $where_clause );
			$cache_group = 'voidempo_eod_data';

			$results = wp_cache_get( $cache_key, $cache_group );

		if ( false === $results ) {

			$results = $wpdb->get_results(
				$wpdb->prepare(
					"
					SELECT e.*, u.display_name, t.task_title, t.task_description,
						p.project_title,
						(SELECT display_name FROM {$wpdb->prefix}users WHERE ID = p.manager_id) AS managername
					FROM {$wpdb->prefix}voidempo_task AS t
					INNER JOIN {$wpdb->prefix}voidempo_eod AS e ON e.task_id = t.id
					INNER JOIN {$wpdb->prefix}voidempo_projects AS p ON e.project_id = p.related_post_id
					INNER JOIN {$wpdb->prefix}users AS u ON u.ID = e.user_id
					WHERE e.is_delete != '1'
					$where_clause
				",
					...$params
				)
			);
			wp_cache_set( $cache_key, $results, $cache_group, MINUTE_IN_SECONDS * 10 );
		}

		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}
		WP_Filesystem();
		global $wp_filesystem;

		$upload_dir  = wp_upload_dir();
		$filename    = 'eod_export_' . time() . '.csv';
		$filepath    = trailingslashit( $upload_dir['basedir'] ) . $filename;
		$fileurl     = trailingslashit( $upload_dir['baseurl'] ) . $filename;
		$csv_output  = '';
		$headers     = array( 'Project Title', 'Manager Name', 'Date', 'Task Title', 'Task Description', 'Employee Name', 'Hours', 'Status', 'Notes' );
		$csv_output .= implode( ',', array_map( 'sanitize_text_field', $headers ) ) . "\n";
		foreach ( $results as $row ) {
			$data = array(
				$row->project_title,
				$row->managername,
				$row->date_created,
				$row->task_title,
				$row->task_description,
				$row->display_name,
				$row->hours,
				$row->status,
				stripslashes( $row->notes ),
			);

			$csv_output .= implode(
				',',
				array_map(
					function ( $field ) {
						return '"' . str_replace( '"', '""', sanitize_text_field( $field ) ) . '"';
					},
					$data
				)
			) . "\n";
		}
		$wp_filesystem->put_contents( $filepath, $csv_output, FS_CHMOD_FILE );

		wp_send_json_success( array( 'file' => $fileurl ) );
	}

	/**
	 * Retrieves missing EOD (End of Day) data for users within a date range.
	 *
	 * This method is typically used to identify which users have not submitted their
	 * EOD reports for specific dates. Can be triggered via AJAX for reporting or alerts.
	 *
	 * @return void Outputs a JSON response containing users with missing EOD data.
	 */
	public function voidempo_missing_eod_data() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );
		
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}


		global $wpdb;
		$duration = isset( $_POST['duration'] ) ? sanitize_text_field( wp_unslash( $_POST['duration'] ) ) : '';

		$stdate = gmdate( 'Y-m-d', strtotime( trim( explode( '-', $duration )[0] ) ) );
		$eddate = gmdate( 'Y-m-d', strtotime( trim( explode( '-', $duration )[1] ) ) );

		$user_i_d = isset( $_POST['employeename'] ) ? sanitize_text_field( wp_unslash( $_POST['employeename'] ) ) : '';

		voidempo_getMissingEodByDateandUser_( $stdate, $eddate, $user_i_d );

		wp_die();
	}

	/**
	 * Exports data to an Excel file.
	 *
	 * This function gathers filtered report or table data and exports it
	 * as an Excel-compatible file (e.g., `.xls` or `.xlsx`). It sets appropriate
	 * headers and outputs the content for download.
	 *
	 * @return void Outputs Excel file and terminates the script.
	 */
	function voidempo_func_export_to_excel3() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );

		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}
		global $wpdb;
		require_once ABSPATH . 'wp-admin/includes/file.php';
		WP_Filesystem();
		global $wp_filesystem;

		$current_user_id     = get_current_user_id();
		$current_user        = wp_get_current_user();
		$is_admin_or_manager = current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' );

		// Sanitize filters.
		$project_filter = isset( $_POST['project_filter'] ) ? intval( $_POST['project_filter'] ) : 0;
		$task_filter    = isset( $_POST['task_filter'] ) ? intval( $_POST['task_filter'] ) : 0;
		$from_date      = ! empty( $_POST['from_date'] ) ? gmdate( 'Y-m-d', strtotime( sanitize_text_field( wp_unslash( $_POST['from_date'] ) ) ) ) : '';
		$to_date        = ! empty( $_POST['to_date'] ) ? gmdate( 'Y-m-d', strtotime( sanitize_text_field( wp_unslash( $_POST['to_date'] ) ) ) ) : '';

		// Build conditions and parameters.
		$conditions = array();
		$params     = array();

		// Date filters.
		if ( $from_date ) {
			$conditions[] = 'DATE(t.date_created) >= %s';
			$params[]     = $from_date;
		}
		if ( $to_date ) {
			$conditions[] = 'DATE(t.date_created) <= %s';
			$params[]     = $to_date;
		}

		// Project filter.
		if ( $project_filter ) {
			$conditions[] = 'vp.related_post_id = %d';
			$params[]     = $project_filter;
		}

		// Task filter.
		if ( $task_filter ) {
			$conditions[] = 't.id = %d';
			$params[]     = $task_filter;
		}

		// Non-admin/manager user filter.
		if ( ! $is_admin_or_manager ) {
			$conditions[] = 'FIND_IN_SET(%d, t.user_id)';
			$params[]     = $current_user_id;
		}

		// Combine all conditions.
		$where_clause = '';
		if ( ! empty( $conditions ) ) {
			$where_clause = ' AND ' . implode( ' AND ', $conditions );
		}

		// Merge static placeholders with dynamic $params.
		$params = array_merge( array( 1, 'voidempo_projects', 'publish' ), $params );

		// Execute safely.
		$results = $wpdb->get_results(
			$wpdb->prepare(
				"
			SELECT 
				vp.project_title,
				(SELECT display_name FROM {$wpdb->prefix}users WHERE ID = t.manager_id) AS manager,
				t.date_created,
				t.task_title,
				t.task_description,
				t.status,
				t.user_id,
				t.id,
				IFNULL(
					(SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(hours))) 
					FROM {$wpdb->prefix}voidempo_eod 
					WHERE is_delete != %d AND task_id = t.id), 
					'00:00:00'
				) AS actualhours,
				(SELECT GROUP_CONCAT(DISTINCT notes SEPARATOR ' | ') 
				FROM {$wpdb->prefix}voidempo_eod 
				WHERE is_delete != 1 AND task_id = t.id) AS all_notes,
				(SELECT GROUP_CONCAT(display_name SEPARATOR ', ')
				FROM {$wpdb->prefix}users
				WHERE FIND_IN_SET(ID, t.user_id) > 0) AS user_names
			FROM {$wpdb->prefix}voidempo_task t
			INNER JOIN {$wpdb->prefix}voidempo_projects vp ON vp.related_post_id = t.project_id
			INNER JOIN {$wpdb->prefix}posts p ON p.ID = vp.related_post_id
			WHERE t.is_delete != 1
			AND p.post_type = %s
			AND p.post_status = %s
			$where_clause
		",
				...$params
			)
		);

		$upload_dir = wp_upload_dir();
		$filename   = 'task_report_' . time() . '.csv';
		$save_path  = trailingslashit( $upload_dir['basedir'] ) . $filename;
		$file_url   = trailingslashit( $upload_dir['baseurl'] ) . $filename;

		$csv_data  = "\xEF\xBB\xBF";
		$csv_data .= implode( ',', array( 'Project Title', 'Manager', 'Date', 'Task Title', 'Task Description', 'User Names', 'Total Hours', 'Status' ) ) . "\n";

		foreach ( $results as $row ) {
			list( $hh, $mm, $ss ) = explode( ':', $row->actualhours );
			$total_hours          = (int) $hh;

			if ( $total_hours >= 24 ) {
				$days            = floor( $total_hours / 24 );
				$remaining_hours = $total_hours % 24;
				$formatted_hours = sprintf( '%d day(s) %02d:%02d:%02d', $days, $remaining_hours, $mm, $ss );
			} else {
				$formatted_hours = sprintf( '%02d:%02d:%02d', $hh, $mm, $ss );
			}

			$data = array(
				$row->project_title,
				$row->manager,
				gmdate( 'Y-m-d', strtotime( $row->date_created ) ),
				$row->task_title,
				$row->task_description,
				$row->user_names,
				$formatted_hours,
				$row->status,
			);

			$csv_data .= '"' . implode(
				'","',
				array_map(
					function ( $f ) {
						return str_replace( '"', '""', $f );
					},
					$data
				)
			) . '"' . "\n";
		}

		$wp_filesystem->put_contents( $save_path, $csv_data, FS_CHMOD_FILE );
		wp_send_json_success( array( 'file_url' => $file_url ) );
	}

	/**
	 * Filters the task list based on input parameters.
	 *
	 * This method is typically used in an AJAX call to return filtered tasks.
	 * Filters may include project ID, assigned user, status, priority, or date range.
	 *
	 * @return void Outputs a JSON response with the filtered task list.
	 */
	public function voidempo_filtertasklist() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}

		global $wpdb;

		$project_id = isset( $_GET['project_id'] ) ? intval( wp_unslash( $_GET['project_id'] ) ) : 0;
		$is_manager = voidempo_fn_check_is_manager_( $project_id, get_current_user_id() );

		$searchablevalues = isset( $_POST['search']['value'] ) ? strtolower( trim( sanitize_text_field( wp_unslash( $_POST['search']['value'] ) ) ) ) : '';

		$orderable_columns = array(
			0 => 'p.project_title',
			1 => 't.task_title',
			2 => 't.task_description',
			3 => "(SELECT GROUP_CONCAT(display_name) FROM {$wpdb->users} WHERE FIND_IN_SET(ID, t.user_id) > 0)",
			4 => 't.status',
			5 => 't.members_status',
			6 => 'TIME_TO_SEC(t.estimated_hours)',
			7 => "(SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(hours))) FROM {$wpdb->prefix}voidempo_eod WHERE task_id = t.id AND is_delete != 1)",
			8 => 't.date_created',
		);

		$order_column_index = isset( $_POST['order'][0]['column'] ) ? intval( $_POST['order'][0]['column'] ) : 0;
		$order_dir_raw      = isset( $_POST['order'][0]['dir'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_POST['order'][0]['dir'] ) ) ) : 'ASC';
		$order_dir          = in_array( $order_dir_raw, array( 'ASC', 'DESC' ), true ) ? $order_dir_raw : 'ASC';

		$order_clause = '';
		if ( isset( $orderable_columns[ $order_column_index ] ) ) {
			$order_clause = "ORDER BY {$orderable_columns[$order_column_index]} $order_dir";
		}

		$start  = isset( $_POST['start'] ) ? intval( $_POST['start'] ) : 0;
		$length = isset( $_POST['length'] ) ? intval( $_POST['length'] ) : 10;

		$cache_key      = 'get_tasks_data_' . md5( $project_id . '_' . $searchablevalues . '_' . $order_column_index . '_' . $order_dir . '_' . $start . '_' . $length );
		$get_tasksdatas = wp_cache_get( $cache_key, 'custom_tasks' );

		if ( false === $get_tasksdatas ) {
			if ( ! empty( $order_clause ) ) {
				$get_tasksdatas .= " $order_clause";
			}

			$get_tasksdatas = $wpdb->get_results(
				$wpdb->prepare(
					"
				SELECT 
					p.project_title, t.id, t.task_title, t.task_description,
					(SELECT GROUP_CONCAT(display_name) FROM {$wpdb->users} WHERE FIND_IN_SET(ID, t.user_id) > 0) AS display_name,
					t.status, t.members_status, t.estimated_hours, t.date_created, t.complete_date,
					(
						SELECT LEFT(SEC_TO_TIME(SUM(TIME_TO_SEC(hours))), CHAR_LENGTH(SEC_TO_TIME(SUM(TIME_TO_SEC(hours)))) - 7)
						FROM {$wpdb->prefix}voidempo_eod 
						WHERE task_id = t.id AND is_delete != 1 AND FIND_IN_SET(user_id, t.user_id) > 0
					) AS actual_hours,
					t.user_id
				FROM {$wpdb->prefix}voidempo_projects AS p
				JOIN {$wpdb->prefix}voidempo_task AS t ON t.project_id = p.related_post_id
				WHERE p.related_post_id = %d
				AND t.is_delete = 0
				GROUP BY t.id, t.user_id
			",
					$project_id
				)
			);

			wp_cache_set( $cache_key, $get_tasksdatas, 'custom_tasks', 600 );
		}

		$jsonarr         = array();
		$jsonarr['draw'] = isset( $_POST['draw'] ) ? intval( wp_unslash( $_POST['draw'] ) ) : 0;
		$filtered_tasks = array();
		$totallength    = 0;

		foreach ( $get_tasksdatas as $task ) {
			$fields_to_search = array(
				strtolower( $task->project_title ),
				strtolower( $task->task_title ),
				strtolower( $task->task_description ),
				strtolower( $task->display_name ),
				strtolower( $task->actual_hours ?: '00:00:00' ),
				strtolower( $task->status ),
				strtolower( str_replace( 'Pending', 'Not Started', $task->members_status ) ),
				strtolower( $task->estimated_hours ),
				strtolower( $task->date_created ),
			);

			if ( empty( $searchablevalues ) || array_filter( $fields_to_search, fn( $v ) => strpos( $v, $searchablevalues ) !== false ) ) {
				if ( $totallength >= $start && count( $filtered_tasks ) < $length ) {
					$filtered_tasks[] = $task;
				}
				++$totallength;
			}
		}

		$jsonarr['recordsTotal']    = $totallength;
		$jsonarr['recordsFiltered'] = $totallength;
		$jsonarr['data']            = array();

		foreach ( $filtered_tasks as $task ) {
			$task_id          = $task->id;
			$project_title    = $task->project_title;
			$task_title       = $task->task_title;
			$user_ids         = explode( ',', $task->user_id );
			$username         = $task->display_name;
			$task_description = $task->task_description;
			$status           = $task->status;
			$estimated_hours  = $task->estimated_hours;
			$actual_hours     = $task->actual_hours ?: '00:00:00';
			$date_created     = $task->date_created;

			$status_map = array(
				'Completed'  => array( 'btn-success', 'Completed' ),
				'Inprogress' => array( 'btn-primary', 'Inprogress' ),
				'Pending'    => array( 'btn-warning', 'Not Started' ),
			);

			$btn_class = $status_map[ $status ][0] ?? 'btn-secondary';
			$html      = $status_map[ $status ][1] ?? $status;
			$attr      = 'disabled';

			// Description cutoff
			$words  = explode( ' ', $task_description );
			$cutoff = '';

			if ( ! empty( $words ) ) {
				$cutoff = array_shift( $words );
				while ( ! empty( $words ) && strlen( $cutoff . ' ' . $words[0] ) <= 60 ) {
					$cutoff .= ' ' . array_shift( $words );
				}
			}

			if ( strlen( trim( $task_description ) ) >= 60 ) {
				$cutoff .= '...';
			}

			$task_deshtml = '<div class="trrepdesc" data-id="' . $task_id . '">
				<div class="divshortdes' . $task_id . '">' . $cutoff . '</div>
				<div class="divlongdes' . $task_id . '" style="display:none;">' . $task_description . '</div>
			</div>';

			$estimatedhtml = '';
			if ( in_array( get_current_user_id(), $user_ids ) ) {
				if ( empty( $estimated_hours ) ) {
					$estimatedhtml .= '<i class="fa fa-pencil visibleestimatededit visibleestimatededit' . $task_id . '" data-task_id="' . $task_id . '" style="cursor:pointer;float:right;" aria-hidden="true"></i>';
				}
				$estimatedhtml .= '<span class="visibleestimatedlbl' . $task_id . '" data-task_id="' . $task_id . '">' . $estimated_hours . '</span>';
			}
			$estimatedhtml .= '<span class="visibleestimatedfld' . $task_id . '" style="display:none;">
				<input type="text" class="esthours esthours' . $task_id . '" value="" placeholder="00:00" data-task_id="' . $task_id . '" />
			</span>';

			$actionhtml = '';
			if ( $is_manager === 'is_manager' || current_user_can( ' manage_options ') || current_user_can( 'voidempo_manager_access' ) ) {
				$actionhtml = '<button class="btn btn-primary open-edit-modal" data-task-id="' . $task_id . '" data-task_user_id="' . implode( ',', $user_ids ) . '">Edit</button>
				<button class="btn btn-danger voidempo_task_delete" data-task_id="' . $task_id . '" data-task_user_id="' . $task->user_id . '">Delete</button>';
			}

			$jsonarr['data'][] = array(
				$project_title,
				$task_title,
				$task_deshtml,
				$username,
				'<div class="voidempo_task_status_td' . $task_id . '"><button ' . $attr . ' class="btn ' . $btn_class . '">' . $html . '</button></div>',
				str_replace( 'Pending', 'Not Started', $task->members_status ),
				$estimatedhtml,
				$actual_hours,
				$date_created,
				$actionhtml,
			);
		}

		if ( empty( $jsonarr['data'] ) ) {
			$jsonarr['data'][] = array_fill( 0, 10, '' );
		}

		echo wp_json_encode( $jsonarr );
		wp_die();
	}


	/**
	 * Filters and returns data for the tabular performance or report list.
	 *
	 * This method is typically triggered via AJAX. It fetches and returns filtered
	 * report data based on input parameters such as employee, date range, or project.
	 *
	 * @return void Outputs a JSON response containing the filtered report list.
	 */
	public function voidempo_filtertablereportlist() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}
		global $wpdb;

		$columns_raw = filter_input( INPUT_POST, 'columns', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_REQUIRE_ARRAY );
		$column      = array();

		if ( is_array( $columns_raw ) ) {
			$columns_raw = wp_unslash( $columns_raw );
			foreach ( $columns_raw as $col ) {
				$column[] = array(
					'data'   => isset( $col['data'] ) ? sanitize_key( $col['data'] ) : '',
					'name'   => isset( $col['name'] ) ? sanitize_text_field( $col['name'] ) : '',
					'search' => array(
						'value' => isset( $col['search']['value'] ) ? sanitize_text_field( wp_unslash( $col['search']['value'] ) ) : '',
						'regex' => isset( $col['search']['regex'] ) ? sanitize_text_field( $col['search']['regex'] ) : 'false',
					),
				);
			}
		}

		$current_user_id = get_current_user_id();
		$is_manager = current_user_can( 'voidempo_manager_access' );


		$where_clauses = array();
		$query_vars    = array();

		if ( ! current_user_can( ' manage_options ') && ! $is_manager ) {
			$where_clauses[] = '(t.manager_id = %d OR FIND_IN_SET(%d, t.user_id) > 0)';
			$query_vars[]    = $current_user_id;
			$query_vars[]    = $current_user_id;
		}

		if ( ! empty( $_POST['from_date'] ) ) {
			$from_date       = gmdate( 'Y-m-d', strtotime( sanitize_text_field( wp_unslash( $_POST['from_date'] ) ) ) );
			$where_clauses[] = 'DATE(t.date_created) >= %s';
			$query_vars[]    = $from_date;
		}
		if ( ! empty( $_POST['to_date'] ) ) {
			$to_date         = gmdate( 'Y-m-d', strtotime( sanitize_text_field( wp_unslash( $_POST['to_date'] ) ) ) );
			$where_clauses[] = 'DATE(t.date_created) <= %s';
			$query_vars[]    = $to_date;
		}

		if ( ! empty( $_POST['project_filter'] ) ) {
			$where_clauses[] = 'vp.related_post_id = %d';
			$query_vars[]    = intval( $_POST['project_filter'] );
		}
		if ( ! empty( $_POST['task_filter'] ) ) {
			$where_clauses[] = 't.id = %d';
			$query_vars[]    = intval( $_POST['task_filter'] );
		}

		for ( $i = 0; $i <= 8; $i++ ) {
			if ( ! empty( $column[ $i ]['search']['value'] ) ) {
				$search = '%' . $wpdb->esc_like( $column[ $i ]['search']['value'] ) . '%';
				switch ( $i ) {
					case 0:
						$where_clauses[] = "(vp.project_title LIKE %s OR vp.status LIKE %s OR (SELECT display_name FROM {$wpdb->prefix}users WHERE ID = t.manager_id) LIKE %s)";
						$query_vars[]    = $search;
						$query_vars[]    = $search;
						$query_vars[]    = $search;
						break;
					case 1:
						$where_clauses[] = '(t.task_title LIKE %s OR t.date_created LIKE %s)';
						$query_vars[]    = $search;
						$query_vars[]    = $search;
						break;
					case 2:
						$where_clauses[] = 't.task_description LIKE %s';
						$query_vars[]    = $search;
						break;
					case 3:
						$where_clauses[] = 't.status LIKE %s';
						$query_vars[]    = $search;
						break;
					case 4:
						$where_clauses[] = '(SELECT GROUP_CONCAT(display_name) FROM ' . $wpdb->prefix . 'users WHERE FIND_IN_SET(ID, t.user_id) > 0) LIKE %s';
						$query_vars[]    = $search;
						break;
					case 5:
						$where_clauses[] = 't.members_status LIKE %s';
						$query_vars[]    = $search;
						break;
					case 6:
						$where_clauses[] = 't.estimated_hours LIKE %s';
						$query_vars[]    = $search;
						break;
					case 7:
						$where_clauses[] = 'IFNULL((SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(hours))) FROM ' . $wpdb->prefix . 'voidempo_eod WHERE is_delete != 1 AND task_id = t.id), "00:00:00") LIKE %s';
						$query_vars[]    = $search;
						break;
					case 8:
						$where_clauses[] = 'SUBTIME(t.estimated_hours, IFNULL((SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(hours))) FROM ' . $wpdb->prefix . 'voidempo_eod WHERE is_delete != 1 AND task_id = t.id), "00:00:00")) LIKE %s';
						$query_vars[]    = $search;
						break;
				}
			}
		}

		$where_sql = ! empty( $where_clauses ) ? ' AND ' . implode( ' AND ', $where_clauses ) : '';

		$order_sql = 'ORDER BY t.id DESC';
		if ( ! empty( $_POST['order'][0]['column'] ) && isset( $_POST['order'][0]['dir'] ) ) {
			$order_column = intval( $_POST['order'][0]['column'] );
			$order_dir    = strtoupper( sanitize_text_field( wp_unslash( $_POST['order'][0]['dir'] ) ) );
			$order_dir    = in_array( $order_dir, array( 'ASC', 'DESC' ) ) ? $order_dir : 'ASC';

			$order_columns = array(
				0 => 'vp.project_title',
				1 => 't.task_title',
				2 => 't.task_description',
				3 => 't.status',
				4 => '(SELECT GROUP_CONCAT(display_name) FROM ' . $wpdb->prefix . 'users WHERE FIND_IN_SET(ID, t.user_id) > 0)',
				5 => 't.members_status',
				6 => 'TIME_TO_SEC(t.estimated_hours)',
				7 => '(SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(`hours`))) FROM ' . $wpdb->prefix . 'voidempo_eod WHERE is_delete != 1 AND task_id = t.id)',
				8 => 'SUBTIME(t.estimated_hours, IFNULL((SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(`hours`))) FROM ' . $wpdb->prefix . 'voidempo_eod WHERE is_delete != 1 AND task_id = t.id), "00:00:00"))',
			);

			if ( isset( $order_columns[ $order_column ] ) ) {
				$order_sql = "ORDER BY {$order_columns[$order_column]} $order_dir";
			}
		}

		$start  = isset( $_POST['start'] ) ? absint( $_POST['start'] ) : 0;
		$length = isset( $_POST['length'] ) ? absint( $_POST['length'] ) : 10;

		$cache_key_data  = 'repdata_' . md5( json_encode( array_merge( $query_vars, array( $start, $length, $order_sql ) ) ) );
		$cache_key_count = 'repdata_count_' . md5( json_encode( $query_vars ) );

		$results        = wp_cache_get( $cache_key_data, 'voidempo_reports' );
		$total_filtered = wp_cache_get( $cache_key_count, 'voidempo_reports' );
		if ( false === $results ) {
			$results = $wpdb->get_results(
				$wpdb->prepare(
					"
				SELECT vp.project_title, vp.status AS project_status, vp.start_date, t.*,
					(SELECT display_name FROM {$wpdb->prefix}users WHERE ID = t.manager_id) AS manager,
					(SELECT GROUP_CONCAT(display_name) FROM {$wpdb->prefix}users WHERE FIND_IN_SET(ID, t.user_id) > 0) AS members,
					IFNULL((SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(hours))) FROM {$wpdb->prefix}voidempo_eod WHERE is_delete != %d AND task_id = t.id), '00:00:00') AS actualhours,
					SUBTIME(t.estimated_hours, IFNULL((SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(hours))) FROM {$wpdb->prefix}voidempo_eod WHERE is_delete != %d AND task_id = t.id), '00:00:00')) AS remainhrs
				FROM {$wpdb->prefix}voidempo_task AS t
				INNER JOIN {$wpdb->prefix}voidempo_projects AS vp ON vp.related_post_id = t.project_id
				INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = vp.related_post_id
				WHERE t.is_delete != %d
				AND p.post_type = %s
				AND p.post_status = %s
				$where_sql
				$order_sql
				LIMIT %d, %d
			",
					...array_merge( array( 1, 1, 1, 'voidempo_projects', 'publish' ), $query_vars, array( $start, $length ) )
				)
			);
			wp_cache_set( $cache_key_data, $results, 'voidempo_reports', HOUR_IN_SECONDS );
		}

		if ( false === $total_filtered ) {
			$total_filtered = $wpdb->get_var(
				$wpdb->prepare(
					"
				SELECT COUNT(t.id)
				FROM {$wpdb->prefix}voidempo_task AS t
				INNER JOIN {$wpdb->prefix}voidempo_projects AS vp ON vp.related_post_id = t.project_id
				INNER JOIN {$wpdb->prefix}posts AS p ON p.ID = vp.related_post_id
				WHERE t.is_delete != %d
				AND p.post_type = %s
				AND p.post_status = %s
				$where_sql
			",
					...array_merge( array( 1, 'voidempo_projects', 'publish' ), $query_vars )
				)
			);
			wp_cache_set( $cache_key_count, $total_filtered, 'voidempo_reports', HOUR_IN_SECONDS );
		}

		$jsonarr = array(
			'draw'            => isset( $_POST['draw'] ) ? intval( wp_unslash( $_POST['draw'] ) ) : 0,
			'recordsTotal'    => $total_filtered,
			'recordsFiltered' => $total_filtered,
			'data'            => array(),
		);

		if ( $results ) {
			foreach ( $results as $rdata ) {
				$remainhrs  = $rdata->remainhrs;
				$taskstatus = $rdata->status;
				$color      = strpos( $remainhrs, '-' ) !== false ? '#ff0000' : ( $taskstatus == 'Completed' ? 'green' : '' );

				$deschtml = '<div class="trrepdesc" data-id="' . $rdata->id . '">
								<div class="divshortdes' . $rdata->id . '">' . wp_kses_post( mb_strimwidth( $rdata->task_description, 0, 60, '...' ) ) . '</div>
								<div class="divlongdes' . $rdata->id . '" style="display:none;">' . wp_kses_post( $rdata->task_description ) . '</div>
							</div>';

				$jsonarr['data'][] = array(
					$rdata->project_title . '<hr>' . $rdata->project_status . '<hr>' . $rdata->start_date . '<hr>' . $rdata->manager,
					$rdata->task_title . '<hr>' . gmdate( 'Y-m-d', strtotime( $rdata->date_created ) ),
					$deschtml,
					$taskstatus,
					$rdata->members,
					$rdata->members_status,
					$rdata->estimated_hours,
					explode( '.', $rdata->actualhours )[0],
					'<span style="color:' . $color . '">' . $remainhrs . '</span>',
				);
			}
		} else {
			$jsonarr['data'][] = array_fill( 0, 9, '' );
		}

		echo wp_json_encode( $jsonarr );
		wp_die();
	}


	/**
	 * Filters and returns EOD (End of Day) summary data based on provided criteria.
	 *
	 * This method is typically triggered via AJAX. It retrieves filtered EOD reports
	 * according to selected parameters like user, date range, or project.
	 *
	 * @return void Outputs a JSON response containing the filtered EOD summary.
	 */
	public function voidempo_filtereodsummary() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 );
			wp_die();
		}

		if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'voidempo_manager_access' ) || current_user_can( 'voidempo_employee_access' )) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized access!' ), 403 );
		}

		global $wpdb;
		$current_uid       = get_current_user_id();
		$current_user      = wp_get_current_user();
		$orderable_columns = array(
			0 => 'v.date_created',
			1 => 'u.display_name',
			2 => 'timeSum',
		);

		$order_index   = isset( $_POST['order'][0]['column'] ) ? absint( wp_unslash( $_POST['order'][0]['column'] ) ) : 0;
		$order_dir_raw = isset( $_POST['order'][0]['dir'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_POST['order'][0]['dir'] ) ) ) : 'ASC';
		$order_column  = isset( $orderable_columns[ $order_index ] ) ? $orderable_columns[ $order_index ] : 'v.date_created';
		$order_dir     = in_array( $order_dir_raw, array( 'ASC', 'DESC' ), true ) ? $order_dir_raw : 'ASC';
		$order_clause  = "ORDER BY $order_column $order_dir";

		$search_value = isset($_POST['search']['value'])
		? strtolower(trim(sanitize_text_field($_POST['search']['value'])))
		: '';

		$where_parts = [];
		$params      = [];

		// --- Base condition ---
		$where_parts[] = 'v.is_delete != %d';
		$params[]      = 1;

		// --- User restrictions ---
		if (
			! current_user_can('manage_options') &&
			! current_user_can('voidempo_manager_access')
		) {
			$where_parts[] = 'v.user_id = %d';
			$params[]      = $current_uid;
		}

		// --- Search filter ---
		if (! empty($search_value)) {
			$search_like = '%' . $wpdb->esc_like($search_value) . '%';
			$where_parts[] = '(LOWER(u.display_name) LIKE %s OR DATE(v.date_created) LIKE %s)';
			$params[]      = $search_like;
			$params[]      = $search_like;
		}

		$where_clause = 'WHERE ' . implode(' AND ', $where_parts);

		// --- Final SQL ---
		$sql = "
			SELECT 
				v.user_id,
				u.display_name,
				v.date_created,
				SEC_TO_TIME(SUM(TIME_TO_SEC(v.hours))) AS timeSum
			FROM {$wpdb->prefix}voidempo_eod AS v
			JOIN {$wpdb->prefix}users AS u ON u.ID = v.user_id
			$where_clause
			GROUP BY v.date_created, v.user_id
			ORDER BY $order_column $order_dir
		";

		$results = $wpdb->get_results(
			$wpdb->prepare($sql, ...$params)
		);

		$eod_summary_res = $results;
		$jsonarr         = array();
		$jsonarr['draw'] = isset( $_POST['draw'] ) ? intval( wp_unslash( $_POST['draw'] ) ) : 0;

		$i             = 0;
		$k             = 0;
		$start         = isset( $_POST['start'] ) ? intval( wp_unslash( $_POST['start'] ) ) : 0;
		$length        = isset( $_POST['length'] ) ? intval( wp_unslash( $_POST['length'] ) ) : 10;
		$paged_results = array();

		foreach ( $eod_summary_res as $res ) {
			$display_name = strtolower( $res->display_name );
			$date_created = $res->date_created;
			$time_sum     = $res->timeSum;

			$match = true;
			if ( $searchablevalues ) {
				$match = false !== strpos( $display_name, $searchablevalues )
					|| false !== strpos( strtolower( $date_created ), $searchablevalues )
					|| false !== strpos( strtolower( $time_sum ), $searchablevalues );
			}

			if ( $match ) {
				if ( $i >= $start && $k < $length ) {
					$paged_results[] = $res;
					++$k;
				}
				++$i;
			}
		}

		$jsonarr['recordsTotal']    = $i;
		$jsonarr['recordsFiltered'] = $i;

		if ( ! empty( $paged_results ) ) {
			foreach ( $paged_results as $res ) {
				$jsonarr['data'][] = array(
					$res->date_created,
					$res->display_name,
					explode( '.', $res->timeSum )[0],
				);
			}
		} else {
			$jsonarr['data'][] = array( '', '', '' );
		}

		echo wp_json_encode( $jsonarr );
		wp_die();
	}
}
