<?php
/**
 * PDF Upload Handler class for managing PDF file uploads.
 *
 * This class handles the upload, validation, and processing of PDF files,
 * including security checks and integration with the PDF handler.
 *
 * @package Askany
 * @since 1.0.0
 */

namespace Askany;

use ask\askany\wpnts_nts_fs;

/**
 * PDF Upload Handler class for managing PDF file uploads.
 *
 * @package Askany
 * @since 1.0.0
 */
class PDFUploadHandler {
	/**
	 * Database instance for content management.
	 *
	 * @var Database
	 */
	private $database;

	/**
	 * PDF Handler instance for processing PDFs.
	 *
	 * @var PDFHandler
	 */
	private $pdf_handler;

	/**
	 * Upload directory for storing PDF files.
	 *
	 * @var string
	 */
	private $upload_dir;

	/**
	 * Constructor for PDFUploadHandler.
	 *
	 * @param Database   $database    Database instance.
	 * @param PDFHandler $pdf_handler PDF Handler instance.
	 */
	public function __construct( $database, $pdf_handler ) {
		$this->database = $database;
		$this->pdf_handler = $pdf_handler;
		$this->upload_dir = wp_upload_dir();
	}

	/**
	 * Initialize upload handler.
	 *
	 * @return void
	 */
	public function init() {
		// Register AJAX handler for PDF upload.
		add_action('wp_ajax_askany_upload_pdf', array( $this, 'handle_pdf_upload' ));
		add_action('wp_ajax_askany_delete_pdf', array( $this, 'handle_pdf_delete' ));
	}

	/**
	 * Handle PDF file upload.
	 *
	 * @return void
	 */
	public function handle_pdf_upload() {
		// Check nonce for security.
		if ( ! isset($_POST['nonce']) || ! wp_verify_nonce(sanitize_text_field( wp_unslash($_POST['nonce'])), 'askany_chat_nonce') ) {
			wp_send_json_error(array( 'message' => 'Security check failed.' ), 403);
		}

		// Check user capabilities.
		if ( ! current_user_can('upload_files') ) {
			wp_send_json_error(array( 'message' => 'You do not have permission to upload files.' ), 403);
		}

		// Check if file was uploaded.
		if ( empty($_FILES['pdf_file']) ) {
			wp_send_json_error(array( 'message' => 'No file was uploaded.' ), 400);
		}

		// Validate file type.
		$file = array(
			'name'     => isset( $_FILES['pdf_file']['name'] ) ? sanitize_file_name( wp_unslash( $_FILES['pdf_file']['name'] ) ) : '',
			'type'     => isset( $_FILES['pdf_file']['type'] ) ? sanitize_text_field( wp_unslash( $_FILES['pdf_file']['type'] ) ) : '',
			'tmp_name' => isset( $_FILES['pdf_file']['tmp_name'] ) ? $_FILES['pdf_file']['tmp_name'] : '', // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- No appropriate direct sanitization function for file paths
			'error'    => isset( $_FILES['pdf_file']['error'] ) ? (int) $_FILES['pdf_file']['error'] : UPLOAD_ERR_NO_FILE,
			'size'     => isset( $_FILES['pdf_file']['size'] ) ? (int) $_FILES['pdf_file']['size'] : 0,
		);
		$file_name = isset($file['name']) ? sanitize_file_name($file['name']) : '';
		$file_type = wp_check_filetype(basename($file_name), array( 'pdf' => 'application/pdf' ));

		if ( $file['type'] !== 'application/pdf' && $file_type['type'] !== 'application/pdf' ) {
			wp_send_json_error(array( 'message' => 'Please upload a valid PDF file.' ), 400);
		}

		// Check for upload errors.
		if ( $file['error'] !== UPLOAD_ERR_OK ) {
			$error_message = $this->get_upload_error_message($file['error']);
			wp_send_json_error(array( 'message' => 'Upload error: ' . $error_message ), 400);
		}

		// Create PDF upload directory if it doesn't exist.
		$upload_dir = $this->upload_dir['basedir'] . '/askany-pdfs';
		if ( ! file_exists($upload_dir) ) {
			wp_mkdir_p($upload_dir);
		}

		// Create .htaccess file for security.
		$htaccess_file = $upload_dir . '/.htaccess';
		if ( ! file_exists($htaccess_file) ) {
			$htaccess_content = "Order deny,allow\nDeny from all";
			file_put_contents($htaccess_file, $htaccess_content);
		}

		// Process the upload.
		$file_name = sanitize_file_name($file['name']);
		$file_path = $upload_dir . '/' . $file_name;
		$counter = 1;

		// Handle duplicate file names.
		while ( file_exists($file_path) ) {
			$file_name = pathinfo(sanitize_file_name($file['name']), PATHINFO_FILENAME) . '-' . $counter . '.pdf';
			$file_path = $upload_dir . '/' . $file_name;
			$counter++;
		}

		// Move uploaded file.
		// The function is actually secure when used properly with proper validation
		// phpcs:ignore Generic.PHP.ForbiddenFunctions.Found
		if ( ! move_uploaded_file($file['tmp_name'], $file_path) ) {
			wp_send_json_error(array( 'message' => 'Failed to save the uploaded file.' ), 500);
		}

		// Process PDF content.
		try {
			// Extract text from the PDF with improved handling.
			$text = $this->pdf_handler->extract_text_from_pdf($file_path);

			if ( empty($text) ) {
				// Try alternative extraction method if primary method fails.
				$text = $this->fallback_text_extraction($file_path);
			}

			if ( empty($text) ) {
				// If text is still empty, report error.
				@unlink($file_path); // Clean up failed file.
				wp_send_json_error(array( 'message' => 'Could not extract text from the PDF. The file may be image-based, password protected, or corrupt.' ), 400);
			}

			// Save to database.
			$result = $this->database->index_pdf($file_name, $file_path, $text);

			if ( $result === false ) {
				// Get more detailed database error.
				global $wpdb;
				$db_error = $wpdb->last_error;
				@unlink($file_path); // Clean up failed file.
				wp_send_json_error(array( 'message' => 'Failed to index the PDF content: ' . $db_error ), 500);
			}

			wp_send_json_success(array(
				'message' => 'PDF uploaded and indexed successfully.',
				'file_name' => $file_name,
			));
		} catch ( \Exception $e ) {
			// Delete the file if processing failed.
			@unlink($file_path);
			wp_send_json_error(array( 'message' => 'Error processing PDF: ' . $e->getMessage() ), 500);
		}
	}

	/**
	 * Get upload error message.
	 *
	 * @param int $error_code Upload error code.
	 * @return string Error message.
	 */
	private function get_upload_error_message( $error_code ) {
		switch ( $error_code ) {
			case UPLOAD_ERR_INI_SIZE:
				return 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
			case UPLOAD_ERR_FORM_SIZE:
				return 'The uploaded file exceeds the MAX_FILE_SIZE directive in the HTML form';
			case UPLOAD_ERR_PARTIAL:
				return 'The uploaded file was only partially uploaded';
			case UPLOAD_ERR_NO_FILE:
				return 'No file was uploaded';
			case UPLOAD_ERR_NO_TMP_DIR:
				return 'Missing a temporary folder';
			case UPLOAD_ERR_CANT_WRITE:
				return 'Failed to write file to disk';
			case UPLOAD_ERR_EXTENSION:
				return 'A PHP extension stopped the file upload';
			default:
				return 'Unknown upload error';
		}
	}

	/**
	 * Fallback method for text extraction from PDF.
	 *
	 * @param string $file_path Path to the PDF file.
	 * @return string Extracted text or empty string on failure.
	 */
	private function fallback_text_extraction( $file_path ) {
		// Try to use exec if available and enabled.
		if ( function_exists('exec') && ! in_array('exec', array_map('trim', explode(',', ini_get('disable_functions')))) ) {
			// Check if pdftotext is available.
			$output = array();
			$return_var = 0;
			exec('which pdftotext', $output, $return_var);

			if ( $return_var === 0 && ! empty($output[0]) ) {
				$temp_txt = tempnam(sys_get_temp_dir(), 'askany_pdf_');
				exec('pdftotext ' . escapeshellarg($file_path) . ' ' . escapeshellarg($temp_txt), $output, $return_var);

				if ( $return_var === 0 && file_exists($temp_txt) ) {
					$text = file_get_contents($temp_txt);
					@unlink($temp_txt);  // Clean up.

					// Process structured formats.
					if ( ! empty($text) ) {
						// Check for Q&A format.
						if ( preg_match('/question\s*:/i', $text) ) {
							$text = $this->format_qa_text($text);
						}

						// Check for Title/Content format.
						if ( preg_match('/title\s*:/i', $text) ) {
							$text = $this->format_title_content_text($text);
						}
					}

					return $text;
				}
			}
		}

		return '';
	}

	/**
	 * Format text in Q&A format.
	 *
	 * @param string $text Text to format.
	 * @return string Formatted text.
	 */
	private function format_qa_text( $text ) {
		// Same implementation as in PdfHandler class.
		// Split by "Question:" or "Q:" patterns.
		$pattern = '/(question\s*:|q\s*:)/i';
		$sections = preg_split($pattern, $text, -1, PREG_SPLIT_NO_EMPTY);

		if ( count($sections) <= 1 ) {
			return $text;
		}

		$formatted = '';
		foreach ( $sections as $section ) {
			// Skip empty sections.
			if ( empty(trim($section)) ) {
				continue;
			}

			// Split into question and answer.
			$parts = preg_split('/(answer\s*:|a\s*:)/i', $section, 2);

			if ( count($parts) > 1 ) {
				$question = trim($parts[0]);
				$answer = trim($parts[1]);
				$formatted .= 'Question: ' . $question . "\nAnswer: " . $answer . "\n\n";
			} else {
				// Handle case where there's no explicit "Answer:" label.
				$formatted .= 'Question: ' . trim($section) . "\n\n";
			}
		}

		return $formatted;
	}


	/**
	 * Format text in Title/Content format.
	 *
	 * @param string $text Text to format.
	 * @return string Formatted text.
	 */
	private function format_title_content_text( $text ) {
		// Same implementation as in PdfHandler class.
		// Split by "Title:" pattern
		$pattern = '/(title\s*:)/i';
		$sections = preg_split($pattern, $text, -1, PREG_SPLIT_NO_EMPTY);

		if ( count($sections) <= 1 ) {
			return $text;
		}

		$formatted = '';
		foreach ( $sections as $section ) {
			// Skip empty sections.
			if ( empty(trim($section)) ) {
				continue;
			}

			// Split into title and content.
			$parts = preg_split('/(content\s*:)/i', $section, 2);

			if ( count($parts) > 1 ) {
				$title = trim($parts[0]);
				$content = trim($parts[1]);
				$formatted .= 'Title: ' . $title . "\nContent: " . $content . "\n\n";
			} else {
				// Handle case where there's no explicit "Content:" label.
				$formatted .= 'Title: ' . trim($section) . "\n\n";
			}
		}

		return $formatted;
	}

	/**
	 * Handle PDF file deletion.
	 *
	 * @return void
	 */
	public function handle_pdf_delete() {
		// Check nonce for security.
		if ( ! isset($_POST['nonce']) || ! wp_verify_nonce(sanitize_text_field( wp_unslash($_POST['nonce'])), 'askany_chat_nonce') ) {
			wp_send_json_error(array( 'message' => 'Security check failed.' ), 403);
		}

		// Check user capabilities.
		if ( ! current_user_can('upload_files') ) {
			wp_send_json_error(array( 'message' => 'You do not have permission to delete files.' ), 403);
		}

		// Check if PDF ID was provided.
		if ( ! isset($_POST['pdf_id']) || empty($_POST['pdf_id']) ) {
			wp_send_json_error(array( 'message' => 'No PDF ID provided.' ), 400);
		}

		// Get PDF file info.
		global $wpdb;
		$tables = $this->database->get_tables();
		$pdf_index_table = $tables['pdf_index'];

		$pdf = $wpdb->get_row($wpdb->prepare(
			"SELECT * FROM $pdf_index_table WHERE id = %d",
			intval($_POST['pdf_id'])
		));

		if ( ! $pdf ) {
			wp_send_json_error(array( 'message' => 'PDF not found.' ), 404);
		}

		// Delete file from filesystem.
		if ( file_exists($pdf->file_path) ) {
			@unlink($pdf->file_path);
		}

		// Delete from database.
		$result = $wpdb->delete(
			$pdf_index_table,
			array( 'id' => intval($_POST['pdf_id']) ),
			array( '%d' )
		);

		if ( $result === false ) {
			wp_send_json_error(array( 'message' => 'Failed to delete PDF from database.' ), 500);
		}

		wp_send_json_success(array( 'message' => 'PDF deleted successfully.' ));
	}
}
