<?php
/**
 * Handles leave application functionality for employees.
 *
 * This class provides methods to create, validate, save, and manage
 * employee leave applications, including duplicate checks and form submissions.
 *
 * @package voidempo
 */
class VOIDEMPO_Leave_Application {

	/**
	 * Class constructor.
	 *
	 * Initializes class properties, hooks, and dependencies required
	 * for the functionality of this component.
	 */
	public function __construct() {

		add_action( 'wp_ajax_voidempo_export_to_excel_leave', array( $this, 'voidempo_export_leave_applications_to_excel' ) );

		add_action( 'wp_ajax_voidempo_get_leave_applications_table_data', array( $this, 'voidempo_get_leave_applications_table_data' ) );
	
		add_action( 'wp_ajax_voidempo_handle_form_submission', array( $this, 'voidempo_handle_form_submission' ) );

	}

	/**
	 * Handles the submission of a leave application or related form.
	 *
	 * This function processes the submitted form data, validates input fields,
	 * saves the data to the database, and returns a response or redirect as needed.
	 *
	 * @return void Outputs a response or performs a redirect after processing.
	 */
	public function voidempo_handle_form_submission() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );

		if ( ! is_user_logged_in() ) {
			wp_safe_redirect( wp_login_url() );
			exit;
		}
		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 );
		}
		if ( isset( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] === 'POST' ) {
			global $wpdb;

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

			$employee_id = isset( $_POST['employee'] ) ? intval( $_POST['employee'] ) : 0;
			$user_id     = ( $is_admin_or_manager && $employee_id ) ? $employee_id : get_current_user_id();

			if ( isset( $_POST['leave-type'], $_POST['from-date'], $_POST['reason'] ) ) {
				$leave_type    = sanitize_text_field( wp_unslash( $_POST['leave-type'] ) );
				$from_date     = sanitize_text_field( wp_unslash( $_POST['from-date'] ) );
				$to_date       = isset( $_POST['to-date'] ) ? sanitize_text_field( wp_unslash( $_POST['to-date'] ) ) : $from_date;
				$reason        = sanitize_textarea_field( wp_unslash( $_POST['reason'] ) );
				$status        = 'Accepted';
				$cache_key     = 'voidempo_holidays_eventstartdata';
				$holiday_dates = wp_cache_get( $cache_key );

				if ( false === $holiday_dates ) {
					global $wpdb;
					$holiday_dates = $wpdb->get_col( "SELECT eventstartdata FROM {$wpdb->prefix}voidempo_holidays" );
					wp_cache_set( $cache_key, $holiday_dates );
				}

				$holiday_dates = array_map(
					function ( $date ) {
						return gmdate( 'Y-m-d', strtotime( $date ) );
					},
					$holiday_dates
				);

				$start      = new DateTime( $from_date );
				$end        = new DateTime( $to_date );
				$interval   = new DateInterval( 'P1D' );
				$date_range = new DatePeriod( $start, $interval, $end->modify( '+1 day' ) );

				$valid_dates = array();
				foreach ( $date_range as $date ) {
					$day = $date->format( 'Y-m-d' );
					if ( ! in_array( $day, $holiday_dates ) ) {
						$valid_dates[] = $day;
					}
				}

				if ( ! empty( $valid_dates ) ) {
					sort( $valid_dates );
					$final_from = reset( $valid_dates );
					$final_to   = end( $valid_dates );

					if ( ! $this->is_duplicate_entry( $user_id, $final_from, $final_to ) ) {
						$result = $this->save_leave_application_data( $user_id, $leave_type, $final_from, $final_to, $reason, $status );

						if ( $result ) {
							$months_to_update = array();
							foreach ( $valid_dates as $date_str ) {
								$month                      = gmdate( 'm', strtotime( $date_str ) );
								$months_to_update[ $month ] = true;
							}

							foreach ( array_keys( $months_to_update ) as $month ) {
								if ( function_exists( 'voidempo_pro_calculate_and_save_leave_details_for_month_' ) ) {
									voidempo_pro_calculate_and_save_leave_details_for_month_( $month, $user_id );
								}
							}
						}

						$response = array(
							'message'      => $result ? 'Leave application submitted successfully' : 'Error submitting leave application',
							'message_type' => $result ? 'success' : 'error',
						);
					} else {
						$response = array(
							'message'      => 'Leave application already exists for the same user and date range',
							'message_type' => 'error',
						);
					}
				} else {
					$response = array(
						'message'      => 'All selected dates fall on holidays. No leave recorded.',
						'message_type' => 'error',
					);
				}

				wp_send_json( $response );
				wp_die();
			}
		}
	}

	/**
	 * Checks if a duplicate leave entry exists for the given user and date range.
	 *
	 * This function verifies whether a leave application already exists for the
	 * specified user between the provided start and end dates.
	 *
	 * @param int    $user_id   The ID of the user.
	 * @param string $from_date The start date of the leave in 'YYYY-MM-DD' format.
	 * @param string $to_date   The end date of the leave in 'YYYY-MM-DD' format.
	 * @return bool True if a duplicate entry exists, false otherwise.
	 */
	public function is_duplicate_entry( $user_id, $from_date, $to_date ) {
		if ( ! is_user_logged_in() ) {
			wp_safe_redirect( wp_login_url() );
			exit;
		}
		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;

		$cache_key   = 'accepted_leave_count_' . md5( $user_id . $from_date . $to_date );
		$cache_group = 'leave_check';

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

		if ( false === $result ) {
			$result = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$wpdb->prefix}leave_applications 
					WHERE user_id = %d 
					AND (
						(from_date <= %s AND to_date >= %s) 
						OR 
						(from_date <= %s AND to_date >= %s)
					) 
					AND status = 'Accepted'",
					$user_id,
					$from_date,
					$from_date,
					$to_date,
					$to_date
				)
			);

			wp_cache_set( $cache_key, $result, $cache_group, 300 );
		}

		return $result > 0;
	}
	/**
	 * Saves a new leave application record for a user.
	 *
	 * This function inserts a leave application into the database with the provided
	 * user ID, leave type, date range, and reason.
	 *
	 * @param int    $user_id    The ID of the user submitting the leave.
	 * @param string $leave_type The type of leave (e.g., 'sick', 'casual').
	 * @param string $from_date  The start date of the leave in 'YYYY-MM-DD' format.
	 * @param string $to_date    The end date of the leave in 'YYYY-MM-DD' format.
	 * @param string $reason    The reason for the leave.
	 * @return bool True on success, false on failure.
	 */
	public function save_leave_application_data( $user_id, $leave_type, $from_date, $to_date, $reason ) {
		if ( ! is_user_logged_in() ) {
			wp_safe_redirect( wp_login_url() );
			exit;
		}
		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;

			$user_name  = get_user_by( 'ID', $user_id )->display_name;
			$table_name = "{$wpdb->prefix}leave_applications";
			$status     = 'Accepted';

			$result = $wpdb->insert(
				$table_name,
				array(
					'user_id'    => $user_id,
					'leave_type' => $leave_type,
					'from_date'  => $from_date,
					'to_date'    => $to_date,
					'reason'     => $reason,
					'status'     => $status,
				)
			);

			return $result;
	}

	/**
	 * Exports leave application records to an Excel file.
	 *
	 * This function retrieves leave applications from the database,
	 * formats them into a spreadsheet (e.g., XLSX or CSV), and sends the
	 * file as a downloadable response for the user.
	 *
	 * @return void Outputs the Excel file directly to the browser.
	 */
	public function voidempo_export_leave_applications_to_excel() {

		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );

		if ( ! is_user_logged_in() ) {
			wp_safe_redirect( wp_login_url() );
			exit;
		}
		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;

		$month   = isset( $_POST['month'] ) ? sanitize_text_field( wp_unslash( $_POST['month'] ) ) : false;
		$year    = isset( $_POST['year'] ) ? sanitize_text_field( wp_unslash( $_POST['year'] ) ) : false;
		$user_id = isset( $_POST['userId'] ) ? sanitize_text_field( wp_unslash( $_POST['userId'] ) ) : null;

		$where_clauses = array();
		$params        = array();

		if ( current_user_can( 'voidempo_manager_access' ) || current_user_can( 'manage_options' ) ) {
			if ( $user_id ) {
				$where_clauses[] = 'user_id = %d';
				$params[]        = $user_id;
			}
		} else {
			$user_id         = get_current_user_id();
			$where_clauses[] = 'user_id = %d';
			$params[]        = $user_id;
		}

		if ( $month ) {
			$where_clauses[] = 'MONTH(from_date) = %d';
			$params[]        = $month;
		}

		if ( $year ) {
			$where_clauses[] = 'YEAR(from_date) = %d';
			$params[]        = $year;
		}

		$where = $where_clauses ? 'WHERE ' . implode( ' AND ', $where_clauses ) : '';
		$order = 'ORDER BY from_date DESC';

		$cache_key   = 'leave_applications_' . md5( $where . $order . serialize( $params ) );
		$cache_group = 'leave_applications_data';

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

		if ( false === $leave_applications ) {
			$leave_applications = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT * FROM {$wpdb->prefix}leave_applications $where $order",
					...$params
				),
				ARRAY_A
			);

			wp_cache_set( $cache_key, $leave_applications, $cache_group, 300 );
		}

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

		$upload_dir  = wp_upload_dir();
		$filename    = 'leave_applications' . '.csv';
		$filepath    = trailingslashit( $upload_dir['basedir'] ) . $filename;
		$fileurl     = trailingslashit( $upload_dir['baseurl'] ) . $filename;
		$csv_output  = '';
		$headers     = array( 'User Name', 'Month', 'Leave Type', 'From Date', 'To Date', 'Reason', 'Status' );
		$csv_output .= implode( ',', array_map( 'sanitize_text_field', $headers ) ) . "\n";

		foreach ( $leave_applications as $row ) {
			$from_date = new DateTime( $row['from_date'] );
			$to_date   = new DateTime( $row['to_date'] );

			$data = array(
				get_user_by( 'ID', $row['user_id'] )->display_name,
				$from_date->format( 'F' ),
				$row['leave_type'],
				$from_date->format( 'd-m-Y' ),
				$to_date->format( 'd-m-Y' ),
				$row['reason'],
				$row['status'],
			);

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

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

	/**
	 * Retrieves leave application data for display in a table format.
	 *
	 * This function fetches leave application records from the database,
	 * typically for rendering in a DataTable or similar UI component.
	 * It may include filtering, pagination, or user-specific leave records.
	 *
	 * @return array An array of leave application data formatted for frontend display.
	 */
	public function voidempo_get_leave_applications_table_data() {
		check_ajax_referer( 'voidempo_dashboard_nonce', 'security' );

		if ( ! is_user_logged_in() ) {
			wp_safe_redirect( wp_login_url() );
			exit;
		}
		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;

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

		$current_user_id = get_current_user_id();
		$month           = ! empty( $_POST['month'] ) ? absint( $_POST['month'] ) : false;
		$year            = ! empty( $_POST['year'] ) ? absint( $_POST['year'] ) : false;

		$where_clauses = array();
		$params        = array();

		// Handle multiple user IDs for managers/admins
		if ( current_user_can( 'voidempo_manager_access' )|| current_user_can( 'manage_options' ) ) {
			if ( ! empty( $_POST['userIds'] ) && is_array( $_POST['userIds'] ) ) {
				$user_ids        = array_map( 'absint', $_POST['userIds'] );
				$placeholders    = implode( ', ', array_fill( 0, count( $user_ids ), '%d' ) );
				$where_clauses[] = "user_id IN ($placeholders)";
				$params          = array_merge( $params, $user_ids );
			} elseif ( ! empty( $_POST['userId'] ) ) {
				$where_clauses[] = 'user_id = %d';
				$params[]        = absint( $_POST['userId'] );
			}
		} else {
			$where_clauses[] = 'user_id = %d';
			$params[]        = $current_user_id;
		}

		if ( $month ) {
			$where_clauses[] = 'MONTH(from_date) = %d';
			$params[]        = $month;
		}

		if ( $year ) {
			$where_clauses[] = 'YEAR(from_date) = %d';
			$params[]        = $year;
		}

		$where_sql = '';
		if ( ! empty( $where_clauses ) ) {
			$where_sql = 'WHERE ' . implode( ' AND ', $where_clauses );
		}

		$cache_key_data    = 'leave_apps_' . md5( serialize( $params ) . "_{$start}_{$length}" );
		$cache_group_data  = 'leave_applications_data';
		$cache_key_count   = 'leave_count_' . md5( serialize( $params ) );
		$cache_group_count = 'leave_applications_count';

		$leave_applications = wp_cache_get( $cache_key_data, $cache_group_data );
		if ( false === $leave_applications ) {
			$params_for_query = array_merge( $params, array( $start, $length ) );

			$leave_applications = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT * FROM {$wpdb->prefix}leave_applications {$where_sql} ORDER BY from_date DESC LIMIT %d, %d",
					...$params_for_query
				),
				ARRAY_A
			);
			wp_cache_set( $cache_key_data, $leave_applications, $cache_group_data, 300 );
		}

		$total_records = wp_cache_get( $cache_key_count, $cache_group_count );
		if ( false === $total_records ) {
			$total_records = (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$wpdb->prefix}leave_applications {$where_sql}",
					...$params
				)
			);
			wp_cache_set( $cache_key_count, $total_records, $cache_group_count, 300 );
		}

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

		foreach ( $leave_applications as $row ) {
			$user      = get_user_by( 'ID', $row['user_id'] );
			$user_name = $user ? $user->display_name : 'Unknown';

			$from_date           = new DateTime( $row['from_date'] );
			$to_date             = new DateTime( $row['to_date'] );
			$month_name          = $from_date->format( 'F' );
			$from_date_formatted = $from_date->format( 'd-m-Y' );
			$to_date_formatted   = $to_date->format( 'd-m-Y' );

			$data_ar = array(
				esc_html( $user_name ),
				esc_html( $month_name ),
				esc_html( $row['leave_type'] ),
				esc_html( $from_date_formatted ),
				esc_html( $to_date_formatted ),
				esc_html( $row['reason'] ),
				esc_html( $row['status'] ),
			);

			if ( $row['status'] === 'Rejected' ) {
				$data_ar[] = '<button class="accept-btn" data-leave-id="' . esc_attr( $row['id'] ) . '">Accept</button>';
			} else {
				$data_ar[] = '<button class="reject-btn" style="background-color:#dc3545;" data-leave-id="' . esc_attr( $row['id'] ) . '">Reject</button>';
			}

			$jsonarr['data'][] = $data_ar;
		}

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