<?php
/**
 * PDF text extraction handler.
 *
 * @package MasterQuiz
 * @since   1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Smalot\PdfParser\Parser;

/**
 * Class MasterQuiz_Pdf_Extractor
 *
 * Extracts text content from PDF files using Smalot PDF Parser.
 *
 * @since 1.0.0
 */
class MasterQuiz_Pdf_Extractor {

	/**
	 * Parser instance.
	 *
	 * @var Parser|null
	 */
	private $parser;

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		$autoload = MASTERQUIZ_PLUGIN_DIR . 'vendor/autoload.php';
		if ( file_exists( $autoload ) ) {
			require_once $autoload;
			$this->parser = new Parser();
		}
	}

	/**
	 * Extract text from a PDF file.
	 *
	 * @since 1.0.0
	 *
	 * @param string $file_path Absolute path to the PDF file.
	 * @return string|WP_Error Extracted text or error.
	 */
	public function extract_text( $file_path ) {
		if ( ! file_exists( $file_path ) ) {
			return new WP_Error( 'file_not_found', esc_html__( 'PDF file not found.', 'masterquiz-ai' ) );
		}

		if ( ! $this->parser ) {
			return new WP_Error(
				'parser_missing',
				esc_html__( 'PDF parser library not installed. Please run "composer install" in the plugin directory.', 'masterquiz-ai' )
			);
		}

		try {
			$pdf  = $this->parser->parseFile( $file_path );
			$text = $pdf->getText();
			$text = $this->clean_text( $text );

			if ( empty( $text ) ) {
				return new WP_Error(
					'empty_text',
					esc_html__( 'No text could be extracted from the PDF. The file may be image-based or corrupted.', 'masterquiz-ai' )
				);
			}

			MasterQuiz_Logger::info( 'PDF text extracted successfully.', array( 'length' => strlen( $text ) ) );

			return $text;

		} catch ( \Exception $e ) {
			MasterQuiz_Logger::error( 'PDF extraction failed.', array( 'error' => $e->getMessage() ) );

			return new WP_Error(
				'extraction_failed',
				/* translators: %s: error message from parser */
				sprintf( esc_html__( 'PDF extraction failed: %s', 'masterquiz-ai' ), $e->getMessage() )
			);
		}
	}

	/**
	 * Get PDF metadata.
	 *
	 * @since 1.0.0
	 *
	 * @param string $file_path Absolute path to the PDF file.
	 * @return array Associative array with title, author, pages.
	 */
	public function get_metadata( $file_path ) {
		if ( ! $this->parser || ! file_exists( $file_path ) ) {
			return array(
				'title'  => 'Unknown',
				'author' => 'Unknown',
				'pages'  => 0,
			);
		}

		try {
			$pdf     = $this->parser->parseFile( $file_path );
			$details = $pdf->getDetails();
			$pages   = $pdf->getPages();

			return array(
				'title'  => isset( $details['Title'] ) ? sanitize_text_field( $details['Title'] ) : 'Untitled',
				'author' => isset( $details['Author'] ) ? sanitize_text_field( $details['Author'] ) : 'Unknown',
				'pages'  => is_array( $pages ) ? count( $pages ) : 0,
			);
		} catch ( \Exception $e ) {
			return array(
				'title'  => 'Unknown',
				'author' => 'Unknown',
				'pages'  => 0,
			);
		}
	}

	/**
	 * Clean and normalise extracted text.
	 *
	 * @since 1.0.0
	 *
	 * @param string $text Raw extracted text.
	 * @return string Cleaned text.
	 */
	private function clean_text( $text ) {
		$text = preg_replace( '/\s+/', ' ', $text );
		$text = preg_replace( '/[^\x20-\x7E\n\r]/', '', $text );
		return trim( $text );
	}

	/**
	 * Split text into sentence-boundary chunks.
	 *
	 * @since 1.0.0
	 *
	 * @param string $text       The full text.
	 * @param int    $max_length Maximum characters per chunk.
	 * @return array Array of text chunks.
	 */
	public function chunk_text( $text, $max_length = 100000 ) {
		if ( strlen( $text ) <= $max_length ) {
			return array( $text );
		}

		$chunks        = array();
		$current_chunk = '';
		$sentences     = preg_split( '/(?<=[.!?])\s+/', $text );

		foreach ( $sentences as $sentence ) {
			if ( strlen( $current_chunk ) + strlen( $sentence ) > $max_length && ! empty( $current_chunk ) ) {
				$chunks[]      = trim( $current_chunk );
				$current_chunk = $sentence;
			} else {
				$current_chunk .= ' ' . $sentence;
			}
		}

		if ( ! empty( $current_chunk ) ) {
			$chunks[] = trim( $current_chunk );
		}

		return $chunks;
	}
}
