<?php
namespace Core\Services;

/**
 * OcrService
 *
 * Handles OCR via OCR.space API.
 * Automatically bypasses the free-tier 3-page PDF limit by:
 *  1. Counting pages in the uploaded PDF (pure PHP, no external tools).
 *  2. Splitting large PDFs into ≤3-page batches using PdfSplitterService.
 *  3. Calling the API once per batch and merging the extracted text.
 *
 * Image files (PNG/JPG) are sent directly — no splitting needed.
 */
class OcrService {
    private string $apiKey;
    private string $endpoint;
    private int    $freePageLimit = 3;

    public function __construct() {
        $config          = require __DIR__ . '/../../config/services.php';
        $this->apiKey    = $config['ocr_space']['api_key'];
        $this->endpoint  = $config['ocr_space']['endpoint'];
    }

    /**
     * Extract text from a file.
     * For PDFs with > 3 pages, automatically splits and merges.
     *
     * @param  string $filePath  Absolute path to uploaded file.
     * @return string            Merged extracted text from all pages.
     * @throws \Exception        On hard failure with no usable text.
     */
    public function extractText(string $filePath): string {
        if (!file_exists($filePath)) {
            throw new \Exception("الملف غير موجود للقراءة.");
        }

        $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));

        // Images go directly — no page limit applies
        if (in_array($ext, ['png', 'jpg', 'jpeg'])) {
            return $this->callOcr($filePath);
        }

        // PDF: check page count and split if needed
        require_once __DIR__ . '/PdfSplitterService.php';
        $splitter  = new PdfSplitterService();
        $pageCount = $splitter->countPages($filePath);
        $batches   = $splitter->split($filePath, $this->freePageLimit);

        $mergedText = '';
        $batchErrors = [];

        foreach ($batches as $batchFile) {
            try {
                $text = $this->callOcr($batchFile);
                $mergedText .= $text . "\n";
            } catch (\Exception $e) {
                $batchErrors[] = $e->getMessage();
            }
        }

        // Cleanup temp files (don't delete the original)
        $splitter->cleanup($batches, $filePath);

        if (empty(trim($mergedText))) {
            $hint = count($batches) > 1
                ? " (تمت معالجة {$pageCount} صفحة على دفعات)"
                : '';
            throw new \Exception(
                "لم يتم التعرف على أي نص طبي في الملف المرفق$hint. " .
                "تأكد من وضوح الصورة." .
                (!empty($batchErrors) ? " | الأخطاء: " . implode(' / ', $batchErrors) : '')
            );
        }

        return $mergedText;
    }

    // ─────────────────────────────────────────────────────────────
    //  INTERNAL: Single OCR API call
    // ─────────────────────────────────────────────────────────────

    /**
     * Send one file (image or small PDF) to OCR.space and return its text.
     *
     * @throws \Exception on complete failure (no text at all).
     */
    private function callOcr(string $filePath): string {
        $cfile    = new \CURLFile($filePath);
        $postData = [
            'apikey'                => $this->apiKey,
            'file'                  => $cfile,
            'language'              => 'eng',       // Medical lab reports are in English
            'isOverlayRequired'     => 'false',
            'isTable'               => 'true',      // Better tabular lab value extraction
            'scale'                 => 'true',      // Better for low-res scans
            'OCREngine'             => '2',         // Engine 2: more accurate, complex layouts
            'detectOrientation'     => 'true',      // Auto-rotate sideways scans
            'isCreateSearchablePDF' => 'false',
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,            $this->endpoint);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST,           1);
        curl_setopt($ch, CURLOPT_POSTFIELDS,     $postData);
        curl_setopt($ch, CURLOPT_TIMEOUT,        90); // Longer timeout for large batches

        // SSL — use system CA bundle if available (XAMPP ships with one)
        $caBundle = 'C:/xampp/php/extras/ssl/cacert.pem';
        if (file_exists($caBundle)) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
            curl_setopt($ch, CURLOPT_CAINFO, $caBundle);
        } else {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200 || !$response) {
            throw new \Exception("فشل الاتصال بخدمة OCR (HTTP {$httpCode}). يرجى المحاولة لاحقاً.");
        }

        $data = json_decode($response, true);

        // Detect page-limit partial success vs real error
        $isError   = $data['IsErroredOnProcessing'] ?? false;
        $errorMsgs = $data['ErrorMessage'] ?? [];
        $pageLimit = false;

        if ($isError && !empty($errorMsgs)) {
            foreach ((array)$errorMsgs as $msg) {
                if (stripos($msg, 'maximum page limit') !== false ||
                    stripos($msg, 'page limit') !== false) {
                    $pageLimit = true;
                    break;
                }
            }
            if (!$pageLimit) {
                throw new \Exception("فشل معالجة الملف: " . implode(' | ', (array)$errorMsgs));
            }
        }

        // Collect text from all parsed pages (even if partial due to page limit)
        $fullText = '';
        if (isset($data['ParsedResults']) && is_array($data['ParsedResults'])) {
            foreach ($data['ParsedResults'] as $result) {
                $fullText .= ($result['ParsedText'] ?? '') . "\n";
            }
        }

        if (empty(trim($fullText))) {
            if ($pageLimit) {
                throw new \Exception(
                    "تجاوز الملف حد الصفحات المسموح، ولم يُقرأ أي نص. " .
                    "جرّب رفع ملف JPG أو PNG لكل صفحة على حدة."
                );
            }
            throw new \Exception("لم يُتعرّف على أي نص في هذا الجزء من الملف.");
        }

        return $fullText;
    }
}
