<?php
/**
 * PDF Handler class for processing PDF files
 *
 * This class handles PDF processing, text extraction, and metadata handling,
 * including integration with various PDF processing libraries.
 *
 * @package Askany
 * @since 1.0.0
 */

namespace Askany;

use ask\askany\wpnts_nts_fs;

/**
 * PDF Handler class for processing PDF files
 *
 * @package Askany
 * @since 1.0.0
 */
class PdfHandler {
	/**
	 * Database instance for content management.
	 *
	 * @var Database
	 */
	private $database;
	/**
	 * Upload directory for storing PDFs.
	 *
	 * @var string
	 */
	private $upload_dir;
	/**
	 * Temporary directory for processing PDFs.
	 *
	 * @var string
	 */
	private $temp_dir;

	/**
	 * Constructor for PdfHandler.
	 *
	 * Initializes the database instance and sets up directories.
	 *
	 * @param Database $database Database instance for content management.
	 */
	public function __construct( $database ) {
		$this->database = $database;
		$this->upload_dir = wp_upload_dir();
		$this->temp_dir = $this->upload_dir['basedir'] . '/askany-temp';
	}

	/**
	 * Initialize the PDF handler.
	 *
	 * Sets up WordPress hooks and creates necessary directories.
	 */
	public function init() {
		// Create necessary directories.
		$this->create_directories();

		// WordPress hooks.
		add_action('add_attachment', array( $this, 'process_pdf_attachment' ));
		add_action('delete_attachment', array( $this, 'delete_pdf_index' ));
		add_action('askany_process_pdf', array( $this, 'process_pdf_file' ));
	}

	/**
	 * Create necessary directories for PDF processing.
	 *
	 * Creates the temporary directory and the PDF storage directory,
	 * including a .htaccess file for security.
	 */
	private function create_directories() {
		// Create temp directory if it doesn't exist.
		if ( ! file_exists($this->temp_dir) ) {
			wp_mkdir_p($this->temp_dir);
		}

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

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

	/**
	 * Process PDF attachment.
	 *
	 * @param int $attachment_id Attachment ID.
	 */
	public function process_pdf_attachment( $attachment_id ) {
		$file = get_attached_file($attachment_id);
		if ( ! $file || ! $this->is_pdf($file) ) {
			return;
		}

		wp_schedule_single_event(time(), 'askany_process_pdf', array( $file, $attachment_id ));
	}

	/**
	 * Process PDF file.
	 *
	 * @param string $file File path.
	 * @param int    $attachment_id Attachment ID.
	 * @return bool True on success, false on failure.
	 */
	public function process_pdf_file( $file, $attachment_id = 0 ) {
		if ( ! file_exists($file) ) {
			// error_log('AskAny PDF Error: File does not exist - ' . $file);
			return false;
		}

		if ( ! $this->is_pdf($file) ) {
			// error_log('AskAny PDF Error: File is not a valid PDF - ' . $file);
			return false;
		}

		// Extract text from PDF.
		$text = $this->extract_text_from_pdf($file);
		if ( empty($text) ) {
			// error_log('AskAny PDF Error: Could not extract text from - ' . $file);
			return false;
		}

		// Get file name for storage.
		$file_name = basename($file);

		// Save to database.
		global $wpdb;
		$tables = $this->database->get_tables();
		$pdf_index_table = $tables['pdf_index'];

		$result = $wpdb->replace(
			$pdf_index_table,
			array(
				'file_path' => $file,
				'file_name' => $file_name,
				'content' => $text,
				'file_size' => filesize($file),
				'attachment_id' => $attachment_id,
				'created_at' => current_time('mysql'),
				'last_updated' => current_time('mysql'),
			),
			array( '%s', '%s', '%s', '%d', '%d', '%s', '%s' )
		);

		if ( $result === false ) {
			// error_log('AskAny PDF Error: Database insertion failed for - ' . $file);
		}

		// Clean up temp files.
		$this->cleanup_temp_files();

		return $result !== false;
	}

	/**
	 * Delete PDF index entry.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return bool True on success, false on failure.
	 */
	public function delete_pdf_index( $attachment_id ) {
		global $wpdb;
		$tables = $this->database->get_tables();
		$pdf_index_table = $tables['pdf_index'];

		// Get file path before deletion.
		$file_path = $wpdb->get_var($wpdb->prepare(
			"SELECT file_path FROM $pdf_index_table WHERE attachment_id = %d",
			$attachment_id
		));

		// Delete from database.
		$result = $wpdb->delete(
			$pdf_index_table,
			array( 'attachment_id' => $attachment_id ),
			array( '%d' )
		);

		// Delete file if it's not in the media library.
		if ( $file_path && ! empty($file_path) && strpos($file_path, 'askany-pdfs') !== false && file_exists($file_path) ) {
			@unlink($file_path);
		}

		return $result;
	}

	/**
	 * Check if the file is a valid PDF.
	 *
	 * @param string $file File path.
	 * @return bool True if valid PDF, false otherwise.
	 */
	private function is_pdf( $file ) {
		if ( ! file_exists($file) ) {
			return false;
		}

		$mime_type = mime_content_type($file);
		return $mime_type === 'application/pdf';
	}

	/**
	 * Extract text from PDF file.
	 *
	 * @param string $file File path.
	 * @return string Extracted text.
	 */
	public function extract_text_from_pdf( $file ) {
		if ( ! class_exists('Smalot\PdfParser\Parser') ) {
			if ( file_exists(ASKANY_PLUGIN_DIR . 'vendor/autoload.php') ) {
				require_once ASKANY_PLUGIN_DIR . 'vendor/autoload.php';
			} else {
				// error_log('PDF Parser library not found');
				return '';
			}
		}

		try {
			$parser = new \Smalot\PdfParser\Parser();
			$pdf = $parser->parseFile($file);
			$text = $pdf->getText();

			// If text is empty or very short, try to extract by pages.
			if ( empty($text) || strlen(trim($text)) < 10 ) {
				$text = $this->extract_text_by_pages($pdf);
			}

			// Process structured formats (Q&A, Title/Content).
			$text = $this->process_structured_text($text);

			return $text;
		} catch ( \Exception $e ) {
			// error_log('PDF Parser Error: ' . $e->getMessage());
			return '';
		}
	}

	/**
	 * Extract text from PDF by pages.
	 *
	 * @param \Smalot\PdfParser\Parser $pdf PDF parser instance.
	 * @return string Extracted text.
	 */
	private function extract_text_by_pages( $pdf ) {
		$text = '';

		// Extract text page by page.
		$pages = $pdf->getPages();
		foreach ( $pages as $page ) {
			$pageText = $page->getText();
			$text .= $pageText . "\n\n";
		}

		return $text;
	}

	/**
	 * Process structured text formats (Q&A, Title/Content).
	 *
	 * @param string $text Text to process.
	 * @return string Processed text.
	 */
	private function process_structured_text( $text ) {
		if ( empty($text) ) {
			return '';
		}

		// Normalize line endings.
		$text = str_replace([ "\r\n", "\r" ], "\n", $text);

		// Try to detect and format question/answer pattern.
		if ( preg_match('/question\s*:/i', $text) ) {
			$text = $this->format_qa_text($text);
		}

		// Try to detect and format title/content pattern.
		if ( preg_match('/title\s*:/i', $text) ) {
			$text = $this->format_title_content_text($text);
		}

		return $text;
	}

	/**
	 * Format Q&A text.
	 *
	 * @param string $text Text to format.
	 * @return string Formatted text.
	 */
	private function format_qa_text( $text ) {
		// 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 Title/Content text.
	 *
	 * @param string $text Text to format.
	 * @return string Formatted text.
	 */
	private function format_title_content_text( $text ) {
		// 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;
	}


	/**
	 * Clean up temporary files.
	 *
	 * Deletes all files in the temporary directory.
	 */
	private function cleanup_temp_files() {
		if ( ! file_exists($this->temp_dir) ) {
			return;
		}

		$files = glob($this->temp_dir . '/*');
		foreach ( $files as $file ) {
			if ( is_file($file) ) {
				unlink($file);
			}
		}
	}

	/**
	 * Get PDF content from the database.
	 *
	 * @param string $file_path File path.
	 * @return string PDF content.
	 */
	public function get_pdf_content( $file_path ) {
		global $wpdb;
		$tables = $this->database->get_tables();
		$pdf_index_table = $tables['pdf_index'];

		$content = $wpdb->get_var($wpdb->prepare(
			"SELECT content FROM $pdf_index_table WHERE file_path = %s",
			$file_path
		));

		if ( ! $content ) {
			$this->process_pdf_file($file_path);
			$content = $wpdb->get_var($wpdb->prepare(
				"SELECT content FROM $pdf_index_table WHERE file_path = %s",
				$file_path
			));
		}

		return $content;
	}

	/**
	 * Get PDF statistics.
	 *
	 * @return array PDF statistics.
	 */
	public function get_pdf_stats() {
		global $wpdb;
		$tables = $this->database->get_tables();
		$pdf_index_table = $tables['pdf_index'];

		return array(
			'total_pdfs' => (int) $wpdb->get_var("SELECT COUNT(*) FROM $pdf_index_table"),
			'total_size' => (int) $wpdb->get_var("SELECT SUM(LENGTH(content)) FROM $pdf_index_table"),
			'last_updated' => $wpdb->get_var("SELECT MAX(last_updated) FROM $pdf_index_table") ?: '—',
		);
	}
}
