<?php

declare(strict_types=1);

namespace SuperAdmin\Controllers;

use App\Helpers\DocumentGenerator;

/**
 * Super Admin Document Controller
 *
 * Phase 5: Handles approval of certificate/marksheet requests from branches.
 *
 * Workflow:
 *   1. Branch submits result → status='pending_approval' (2 rows: cert + marksheet)
 *   2. Super Admin sees pending requests in /super-admin/documents
 *   3. Super Admin clicks "Approve & Generate" →
 *      a. Deducts ₹200 from branch wallet (if online payment)
 *      b. Generates PDF using Pattern System (cert + marksheet)
 *      c. Updates status='generated' + saves pdf_path
 *      d. Updates pattern_id in certificates table
 *   4. Branch can now download both PDFs from /branch/documents
 *
 * PDF Generation Uses Pattern System:
 *   - Pattern loaded from: certificates.pattern_id OR courses.cert_pattern_id
 *   - Background image from: certificate_patterns.cert_background_path
 *   - Fields from: certificate_pattern_fields (WHERE is_enabled = 1)
 */
class SuperAdminDocumentController extends SuperAdminBaseController
{
    /**
     * List all document requests (filterable by status).
     */
    public function index(): void
    {
        requireSuperAdmin();

        $statusFilter = trim($_GET['status'] ?? '');

        $sql = "SELECT c.*,
                       COALESCE(c.student_name, u.name, s2.name, 'Unknown') AS student_name,
                       COALESCE(c.course_name, cs.name, '—') AS course_name,
                       s.enrollment_no,
                       t.name AS template_name, t.type AS doc_type,
                       b.name AS branch_name, b.branch_code
                FROM certificates c
                LEFT JOIN students s ON c.student_id = s.id
                LEFT JOIN users u ON s.user_id = u.id
                LEFT JOIN students s2 ON c.student_id = s2.id
                LEFT JOIN courses cs ON c.course_id = cs.id
                LEFT JOIN certificate_templates t ON c.template_id = t.id
                LEFT JOIN branches b ON c.branch_id = b.id
                WHERE 1=1";
        $params = [];
        if ($statusFilter && in_array($statusFilter, ['pending_approval','generated','rejected','cancelled'], true)) {
            $sql .= " AND c.status = :status";
            $params[':status'] = $statusFilter;
        }
        $sql .= " ORDER BY c.created_at DESC";

        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        $documents = $stmt->fetchAll() ?: [];

        $stats = ['pending' => 0, 'generated' => 0, 'rejected' => 0, 'total' => count($documents)];
        foreach ($documents as $d) {
            $status = $d['status'] ?? '';
            if ($status === 'pending_approval') $stats['pending']++;
            elseif ($status === 'generated') $stats['generated']++;
            elseif ($status === 'rejected') $stats['rejected']++;
        }

        $this->superAdminView('documents/index', [
            'title'        => 'Document Approvals',
            'currentPage'  => 'documents',
            'documents'    => $documents,
            'statusFilter' => $statusFilter,
            'stats'        => $stats,
        ]);
    }

    /**
     * Show a single document request with full details.
     */
    public function show(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id || $id <= 0) {
            flash('error', 'Invalid document ID.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        $stmt = $this->db->prepare(
            "SELECT c.*,
                    COALESCE(c.student_name, u.name, 'Unknown') AS student_name,
                    s.enrollment_no, s.father_name, s.dob,
                    s.admission_date, s.guardian_name,
                    COALESCE(c.course_name, cs.name, '—') AS course_name,
                    cs.duration, cs.subjects AS course_subjects,
                    t.name AS template_name, t.type AS doc_type, t.background_image,
                    t.template_width, t.template_height,
                    b.name AS branch_name, b.branch_code
             FROM certificates c
             LEFT JOIN students s ON c.student_id = s.id
             LEFT JOIN users u ON s.user_id = u.id
             LEFT JOIN courses cs ON c.course_id = cs.id
             LEFT JOIN certificate_templates t ON c.template_id = t.id
             LEFT JOIN branches b ON c.branch_id = b.id
             WHERE c.id = :id LIMIT 1"
        );
        $stmt->execute([':id' => $id]);
        $document = $stmt->fetch() ?: null;
        if (!$document) {
            flash('error', 'Document not found.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        $stmt = $this->db->prepare("SELECT * FROM certificate_timeline WHERE certificate_id = :cid ORDER BY created_at ASC");
        $stmt->execute([':cid' => $id]);
        $timeline = $stmt->fetchAll() ?: [];

        $subjectsData = [];
        if (!empty($document['subjects_json'])) {
            $decoded = json_decode($document['subjects_json'], true);
            if (is_array($decoded)) $subjectsData = $decoded;
        }

        $walletBalance = 0;
        $stmt = $this->db->prepare("SELECT wallet_balance FROM branches WHERE id = :bid LIMIT 1");
        $stmt->execute([':bid' => $document['branch_id']]);
        $walletBalance = (float)($stmt->fetchColumn() ?: 0);

        $this->superAdminView('documents/show', [
            'title'        => 'Document: ' . ($document['certificate_no'] ?? ''),
            'currentPage'  => 'documents',
            'document'     => $document,
            'timeline'     => $timeline,
            'subjectsData' => $subjectsData,
            'walletBalance'=> $walletBalance,
        ]);
    }

    /**
     * Approve a document request + deduct wallet + generate PDF using Pattern System.
     */
    public function approve(?int $id = null): void
    {
        requireSuperAdmin();
        $this->validateCsrf();

        if (!$id || $id <= 0) {
            flash('error', 'Invalid document ID.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        // ─── Fetch document with all related data ─────────────────────────
        $stmt = $this->db->prepare(
            "SELECT c.*,
                    COALESCE(c.student_name, u.name, 'Unknown') AS student_name,
                    s.enrollment_no, s.father_name, s.mother_name,
                    s.dob, s.admission_date, s.guardian_name,
                    COALESCE(c.course_name, cs.name, '—') AS course_name,
                    cs.duration,
                    cs.cert_pattern_id, cs.marksheet_pattern_id,
                    t.name AS template_name, t.type AS doc_type, t.background_image,
                    t.template_width, t.template_height,
                    b.name AS branch_name, b.branch_code
             FROM certificates c
             LEFT JOIN students s ON c.student_id = s.id
             LEFT JOIN users u ON s.user_id = u.id
             LEFT JOIN courses cs ON c.course_id = cs.id
             LEFT JOIN certificate_templates t ON c.template_id = t.id
             LEFT JOIN branches b ON c.branch_id = b.id
             WHERE c.id = :id LIMIT 1"
        );
        $stmt->execute([':id' => $id]);
        $doc = $stmt->fetch() ?: null;

        if (!$doc) {
            flash('error', 'Document not found.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        $currentStatus = $doc['status'] ?? '';
        if (in_array($currentStatus, ['generated', 'approved', 'rejected', 'cancelled'], true)) {
            flash('error', 'Document already processed (current status: ' . $currentStatus . ').');
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        // ─── Determine which pattern to use (certificate or marksheet) ────
        $docType = $doc['doc_type'] ?? 'certificate';  // 'certificate' or 'marksheet'
        $patternId = $doc['pattern_id'] ?? null;

        if (!$patternId) {
            // Fallback to course's pattern for this doc type
            $patternId = $docType === 'marksheet'
                ? ($doc['marksheet_pattern_id'] ?? null)
                : ($doc['cert_pattern_id'] ?? null);
        }

        if (!$patternId) {
            // Fallback to default locked pattern
            $stmt = $this->db->query("SELECT id FROM certificate_patterns WHERE is_default = 1 AND status = 'locked' LIMIT 1");
            $default = $stmt->fetch();
            $patternId = $default['id'] ?? null;
        }

        if (!$patternId) {
            flash('error', 'No pattern assigned to this course. Assign a pattern via "Assign to Courses" page first.');
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        // ─── Load pattern record ──────────────────────────────────────────
        $stmt = $this->db->prepare("SELECT * FROM certificate_patterns WHERE id = :pid AND status = 'locked' LIMIT 1");
        $stmt->execute([':pid' => $patternId]);
        $pattern = $stmt->fetch() ?: null;

        if (!$pattern) {
            flash('error', "Pattern ID {$patternId} not found or not locked.");
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        // Determine background path for this doc type
        $bgPath = $docType === 'certificate'
            ? ($pattern['cert_background_path'] ?? '')
            : ($pattern['marksheet_background_path'] ?? '');

        if (empty($bgPath)) {
            flash('error', "Pattern '{$pattern['name']}' has no background image for {$docType}. Upload JPG in pattern editor.");
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        // ─── Load pattern fields for this doc type ────────────────────────
        $stmt = $this->db->prepare(
            "SELECT * FROM certificate_pattern_fields
             WHERE pattern_id = :pid AND doc_type = :dt AND is_enabled = 1
             ORDER BY id ASC"
        );
        $stmt->execute([':pid' => $patternId, ':dt' => $docType]);
        $fields = $stmt->fetchAll() ?: [];

        // ─── Parse subjects JSON ──────────────────────────────────────────
        $subjectsData = [];
        if (!empty($doc['subjects_json'])) {
            $subjectsData = json_decode($doc['subjects_json'], true) ?: [];
        }

        // Build subjects array for marksheet
        $subjects = [];
        if ($docType === 'marksheet' && !empty($subjectsData['subjects'])) {
            $subjList = $subjectsData['subjects'];
            $maxList  = $subjectsData['max_marks'] ?? [];
            $obtList  = $subjectsData['obtained_marks'] ?? [];
            for ($i = 0; $i < count($subjList); $i++) {
                $subjects[] = [
                    'name'     => $subjList[$i] ?? 'Subject ' . ($i + 1),
                    'max'      => (int)($maxList[$i] ?? 100),
                    'obtained' => (int)($obtList[$i] ?? 0),
                ];
            }
        }

        // ─── Fetch student photo ──────────────────────────────────────────
        $photoPath = '';
        $stmt2 = $this->db->prepare("SELECT u.photo FROM students s LEFT JOIN users u ON s.user_id = u.id WHERE s.id = :sid LIMIT 1");
        $stmt2->execute([':sid' => $doc['student_id']]);
        $photoRow = $stmt2->fetch();
        if ($photoRow && !empty($photoRow['photo'])) {
            $photoPath = $photoRow['photo'];
        }

        // ─── Fetch student address ────────────────────────────────────────
        $addrLine = '';
        $stmt3 = $this->db->prepare("SELECT address, city, state, pin_code FROM students WHERE id = :sid LIMIT 1");
        $stmt3->execute([':sid' => $doc['student_id']]);
        $addrRow = $stmt3->fetch();
        if ($addrRow) {
            $parts = array_filter([$addrRow['address'] ?? '', $addrRow['city'] ?? '', $addrRow['state'] ?? '', $addrRow['pin_code'] ?? '']);
            $addrLine = implode(', ', $parts);
        }

        // ─── Build division ───────────────────────────────────────────────
        $pct = (float)($doc['percentage'] ?? 0);
        $division = $doc['division'] ?? 'Fail';
        if (empty($doc['division'])) {
            if ($pct >= 60) $division = 'First Division';
            elseif ($pct >= 45) $division = 'Second Division';
            elseif ($pct >= 33) $division = 'Third Division';
        }

        // ─── Calculate session dates ──────────────────────────────────────
        // ✅ PRIORITY 1: Use labels stored in subjects_json (set by BranchCertGenController)
        // ✅ PRIORITY 2: Calculate from admission_date + course duration (inclusive)
        // ✅ PRIORITY 3: Use session_from/session_to columns
        $fromLabel = $subjectsData['from_label'] ?? '';
        $toLabel   = $subjectsData['to_label'] ?? '';

        // If labels are missing, calculate from admission_date + course duration
        if (empty($fromLabel) || empty($toLabel)) {
            $admissionDate = $doc['admission_date'] ?? null;
            $courseDuration = $doc['duration'] ?? '';

            if ($admissionDate && $courseDuration) {
                $fromDt = \DateTime::createFromFormat('Y-m-d', $admissionDate);
                if ($fromDt) {
                    if (empty($fromLabel)) {
                        $fromLabel = strtoupper($fromDt->format('M Y'));
                    }
                    if (empty($toLabel)) {
                        $toDt = clone $fromDt;
                        $this->addDurationToDate($toDt, $courseDuration);
                        $toLabel = strtoupper($toDt->format('M Y'));
                    }
                }
            }
        }

        // Fallback: use session_from/session_to if still empty
        if (empty($fromLabel) && !empty($doc['session_from'])) {
            $dt = \DateTime::createFromFormat('Y-m-d', $doc['session_from']);
            if ($dt) $fromLabel = strtoupper($dt->format('M Y'));
        }
        if (empty($toLabel) && !empty($doc['session_to'])) {
            $dt = \DateTime::createFromFormat('Y-m-d', $doc['session_to']);
            if ($dt) $toLabel = strtoupper($dt->format('M Y'));
        }

        // ─── Resolve photo path (try multiple locations) ──────────────────
        if (!empty($photoPath)) {
            $resolvedPhotoPath = $this->resolvePhotoPath($photoPath);
            error_log("Photo path resolution: original={$photoPath}, resolved={$resolvedPhotoPath}, exists=" . (file_exists($resolvedPhotoPath) ? 'YES' : 'NO'));
            $photoPath = $resolvedPhotoPath;
        } else {
            error_log("Photo path is EMPTY for certificate ID: {$id}, student_id: {$doc['student_id']}");
        }

        // ─── Build student data array ─────────────────────────────────────
        $studentData = [
            'student_name'    => $doc['student_name'] ?? '',
            'father_name'     => $doc['father_name'] ?? $doc['guardian_name'] ?? '',
            'mother_name'     => $doc['mother_name'] ?? '',
            'enrollment_no'   => $doc['enrollment_no'] ?? '',
            'certificate_no'  => $doc['certificate_no'] ?? '',
            'percentage'      => ($doc['percentage'] ?? 0) . '%',
            'grade'           => $doc['grade'] ?? '',
            'division'        => $division,
            'branch_name'     => $doc['branch_name'] ?? '',
            'branch_code'     => $doc['branch_code'] ?? '',
            'course'          => $doc['course_name'] ?? '',
            'duration'        => $doc['duration'] ?? '',
            'date_of_issue'   => !empty($doc['issue_date']) ? date('d/m/Y', strtotime($doc['issue_date'])) : date('d/m/Y'),
            'from_date'       => $fromLabel,
            'to_date'         => $toLabel,
            'verification_url'=> $doc['verification_url'] ?? '',
            'qr_code'         => $doc['verification_url'] ?? '',
            'qr_data'         => $doc['verification_url'] ?? $doc['certificate_no'] ?? '',
            'institute_name'  => 'Gmind Institute',
            'photo'           => $photoPath,
            'address'         => $addrLine,
            'subjects'        => $subjects,
        ];

        try {
            // ─── 1. Deduct from wallet (if online payment) ──────────────────
            $amountPaid = (float)($doc['amount_paid'] ?? 0);
            $paymentMode = $doc['payment_mode'] ?? 'offline';
            $isOnline = in_array($paymentMode, ['online', 'upi', 'wallet'], true);

            if ($isOnline && $amountPaid > 0) {
                $this->db->prepare(
                    "UPDATE branches SET wallet_balance = wallet_balance - :amt WHERE id = :bid"
                )->execute([':amt' => $amountPaid, ':bid' => $doc['branch_id']]);

                $this->db->prepare(
                    "INSERT INTO branch_wallet_transactions
                        (branch_id, type, amount, balance_after, description, category, reference_type, reference_id, created_by, created_at)
                     VALUES (:bid, 'debit', :amt, 0, :desc, 'document', 'certificate', :ref, :uid, NOW())"
                )->execute([
                    ':bid'  => $doc['branch_id'],
                    ':amt'  => $amountPaid,
                    ':desc' => "Document approved: {$doc['certificate_no']} ({$docType})",
                    ':ref'  => $id,
                    ':uid'  => $_SESSION['user_id'] ?? null,
                ]);
            }

            // ─── 2. Generate PDF using Pattern System ───────────────────────
            $generator = new DocumentGenerator();
            $pdf = $generator->generateFromPattern([
                'pattern'    => $pattern,
                'fields'     => $fields,
                'student'    => $studentData,
                'doc_type'   => $docType,
                'bg_path'    => $bgPath,
                'is_preview' => false,
            ]);

            // Save PDF to disk — try multiple directories
            $candidateDirs = [
                $_SERVER['DOCUMENT_ROOT'] . '/uploads/certificates/',
                '/home/advaysin/public_html/uploads/certificates/',
                dirname(dirname(dirname(dirname(__DIR__)))) . '/uploads/certificates/',
            ];

            $uploadDir = null;
            foreach ($candidateDirs as $dir) {
                if (!is_dir($dir)) {
                    @mkdir($dir, 0755, true);
                }
                if (is_dir($dir) && is_writable($dir)) {
                    $uploadDir = $dir;
                    break;
                }
            }

            if (!$uploadDir) {
                throw new \Exception("Cannot find writable directory for PDF. Tried: " . implode(', ', $candidateDirs));
            }

            $filename = $docType . '_' . $id . '_' . time() . '.pdf';
            $filePath = $uploadDir . $filename;

            // Save PDF
            $pdf->Output('F', $filePath);

            // ✅ VERIFY: File actually saved?
            if (!file_exists($filePath)) {
                throw new \Exception("PDF save failed — file not created at: " . $filePath);
            }

            $fileSize = filesize($filePath);
            if ($fileSize < 1000) {
                throw new \Exception("PDF save failed — file too small ({$fileSize} bytes) at: " . $filePath);
            }

            // Build relative path (strip DOCUMENT_ROOT if possible)
            $pdfRelPath = '/uploads/certificates/' . $filename;
            $docRoot = $_SERVER['DOCUMENT_ROOT'];
            if (strpos($filePath, $docRoot) === 0) {
                $pdfRelPath = substr($filePath, strlen($docRoot));
            }

            error_log("PDF generated successfully: {$filePath} ({$fileSize} bytes), stored path: {$pdfRelPath}");

            // ─── 3. Update certificate record ───────────────────────────────
            $this->db->prepare(
                "UPDATE certificates
                 SET status = 'generated',
                     pdf_path = :path,
                     pattern_id = :pid,
                     updated_at = NOW()
                 WHERE id = :id"
            )->execute([
                ':path' => $pdfRelPath,
                ':pid'  => $patternId,
                ':id'   => $id,
            ]);

            // ─── 4. Timeline entry ──────────────────────────────────────────
            $this->db->prepare(
                "INSERT INTO certificate_timeline (certificate_id, event, description, created_at)
                 VALUES (:cid, 'approved', :desc, NOW())"
            )->execute([
                ':cid'  => $id,
                ':desc' => "Approved by Super Admin. PDF generated using Pattern '{$pattern['name']}' ({$fileSize} bytes)." . ($isOnline ? " ₹{$amountPaid} deducted from branch wallet." : ""),
            ]);

            $this->auditLog('document_approve', 'certificates', $id,
                "Approved document #{$doc['certificate_no']} ({$docType}). PDF generated via Pattern System ({$fileSize} bytes)." . ($isOnline ? " Wallet debited ₹{$amountPaid}." : ""));

            flash('success', "✅ Document approved! PDF generated successfully ({$fileSize} bytes)." . ($isOnline ? " ₹{$amountPaid} deducted from branch wallet." : "") . " Branch can now download the PDF.");

        } catch (\Throwable $e) {
            error_log('SuperAdmin approve error: ' . $e->getMessage() . "\n" . $e->getTraceAsString());

            // Don't mark as generated if PDF failed — keep as pending so super admin can retry
            $this->db->prepare(
                "INSERT INTO certificate_timeline (certificate_id, event, description, created_at)
                 VALUES (:cid, 'approved', :desc, NOW())"
            )->execute([
                ':cid'  => $id,
                ':desc' => "PDF generation FAILED: " . $e->getMessage() . ". Document remains pending. Fix issue and re-approve.",
            ]);

            flash('error', "❌ PDF generation failed: " . $e->getMessage() . ". Document not marked as generated. Please fix the issue and re-approve.");
        }

        redirect(BASE_PATH . '/super-admin/documents/' . $id);
    }

    /**
     * Download/View PDF from Super Admin panel
     */
    public function downloadPdf(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id || $id <= 0) {
            flash('error', 'Invalid document ID.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        // Load certificate
        $stmt = $this->db->prepare(
            "SELECT c.*,
                    COALESCE(c.student_name, u.name, 'Unknown') AS student_name,
                    t.name AS template_name, t.type AS doc_type
             FROM certificates c
             LEFT JOIN students s ON c.student_id = s.id
             LEFT JOIN users u ON s.user_id = u.id
             LEFT JOIN certificate_templates t ON c.template_id = t.id
             WHERE c.id = :id LIMIT 1"
        );
        $stmt->execute([':id' => $id]);
        $doc = $stmt->fetch() ?: null;

        if (!$doc) {
            flash('error', 'Document not found.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        if ($doc['status'] !== 'generated') {
            flash('error', 'Document not yet approved/generated.');
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        $pdfPath = $doc['pdf_path'] ?? '';
        if (empty($pdfPath)) {
            flash('error', 'PDF file not found. Please regenerate.');
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        // Multi-path resolution
        $candidates = [
            $pdfPath,
            $_SERVER['DOCUMENT_ROOT'] . $pdfPath,
            $_SERVER['DOCUMENT_ROOT'] . '/' . ltrim($pdfPath, '/'),
            rtrim($_SERVER['DOCUMENT_ROOT'], '/') . $pdfPath,
            $_SERVER['DOCUMENT_ROOT'] . '/gmind' . $pdfPath,
            '/home/advaysin/public_html' . $pdfPath,
            '/home/advaysin/public_html/gmind' . $pdfPath,
        ];

        if ($pdfPath[0] !== '/') {
            $candidates[] = $_SERVER['DOCUMENT_ROOT'] . '/' . $pdfPath;
            $candidates[] = '/home/advaysin/public_html/' . $pdfPath;
            $candidates[] = '/home/advaysin/public_html/gmind/' . $pdfPath;
        }

        $filePath = null;
        foreach ($candidates as $cand) {
            if (file_exists($cand) && is_readable($cand)) {
                $filePath = $cand;
                break;
            }
        }

        if (!$filePath) {
            flash('error', 'PDF file not found on server. Tried: ' . implode(', ', array_slice($candidates, 0, 3)));
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        $studentName = preg_replace('/[^a-zA-Z0-9]/', '_', $doc['student_name'] ?? 'student');
        $downloadName = ($doc['doc_type'] ?? 'doc') . '_' . $studentName . '_' . ($doc['certificate_no'] ?? $id) . '.pdf';

        // Get mode: 'view' (inline) or 'download' (attachment)
        $mode = $_GET['mode'] ?? 'view';

        header('Content-Type: application/pdf');
        if ($mode === 'download') {
            header('Content-Disposition: attachment; filename="' . $downloadName . '"');
        } else {
            header('Content-Disposition: inline; filename="' . $downloadName . '"');
        }
        header('Content-Length: ' . filesize($filePath));
        header('Cache-Control: private, max-age=0, must-revalidate');

        while (ob_get_level()) ob_end_clean();
        readfile($filePath);
        exit;
    }

    /**
     * Download combined Certificate + Marksheet PDF (Super Admin)
     */
    public function downloadCombined(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id || $id <= 0) {
            flash('error', 'Invalid document ID.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        // Load certificate
        $stmt = $this->db->prepare(
            "SELECT c.*, t.type AS doc_type
             FROM certificates c
             LEFT JOIN certificate_templates t ON c.template_id = t.id
             WHERE c.id = :id LIMIT 1"
        );
        $stmt->execute([':id' => $id]);
        $doc = $stmt->fetch() ?: null;

        if (!$doc) {
            flash('error', 'Document not found.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        // Find sibling (cert or marksheet)
        $stmt = $this->db->prepare(
            "SELECT c.*, t.type AS doc_type
             FROM certificates c
             LEFT JOIN certificate_templates t ON c.template_id = t.id
             WHERE c.student_id = :sid AND c.course_id = :cid AND c.id != :id
                 AND c.status = 'generated'
             LIMIT 1"
        );
        $stmt->execute([
            ':sid' => $doc['student_id'],
            ':cid' => $doc['course_id'],
            ':id'  => $id,
        ]);
        $sibling = $stmt->fetch() ?: null;

        if (!$sibling) {
            flash('error', 'Sibling document not found. Both cert + marksheet must be approved.');
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        $pdf1 = \App\Helpers\CombinedPdfHelper::resolvePdfPath($doc['pdf_path'] ?? '');
        $pdf2 = \App\Helpers\CombinedPdfHelper::resolvePdfPath($sibling['pdf_path'] ?? '');

        if (!$pdf1 || !$pdf2) {
            flash('error', 'One or both PDF files not found.');
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        $tempFile = sys_get_temp_dir() . '/combined_admin_' . $id . '_' . time() . '.pdf';
        $success = \App\Helpers\CombinedPdfHelper::combine($pdf1, $pdf2, $tempFile);

        if (!$success || !file_exists($tempFile)) {
            flash('error', 'Failed to combine PDFs.');
            redirect(BASE_PATH . '/super-admin/documents/' . $id);
        }

        $studentName = preg_replace('/[^a-zA-Z0-9]/', '_', $doc['student_name'] ?? 'student');
        $downloadName = 'Combined_' . $studentName . '_' . $doc['certificate_no'] . '.pdf';

        header('Content-Type: application/pdf');
        header('Content-Disposition: attachment; filename="' . $downloadName . '"');
        header('Content-Length: ' . filesize($tempFile));
        while (ob_get_level()) ob_end_clean();
        readfile($tempFile);
        @unlink($tempFile);
        exit;
    }

    /**
     * Reject a document request.
     */
    public function reject(?int $id = null): void
    {
        requireSuperAdmin();
        $this->validateCsrf();

        $reason = trim($_POST['reason'] ?? 'No reason provided');

        $stmt = $this->db->prepare("SELECT * FROM certificates WHERE id = :id LIMIT 1");
        $stmt->execute([':id' => $id]);
        $doc = $stmt->fetch() ?: null;
        if (!$doc) {
            flash('error', 'Document not found.');
            redirect(BASE_PATH . '/super-admin/documents');
        }

        $this->db->prepare("UPDATE certificates SET status = 'rejected', updated_at = NOW() WHERE id = :id")
            ->execute([':id' => $id]);

        $this->db->prepare(
            "INSERT INTO certificate_timeline (certificate_id, event, description, created_at)
             VALUES (:cid, 'rejected', :desc, NOW())"
        )->execute([
            ':cid'  => $id,
            ':desc' => "Rejected by Super Admin. Reason: {$reason}",
        ]);

        $this->auditLog('document_reject', 'certificates', $id, "Rejected document #{$doc['certificate_no']}: {$reason}");
        flash('success', 'Document rejected. The branch has been notified.');
        redirect(BASE_PATH . '/super-admin/documents');
    }

    /**
     * Resolve photo path — try multiple locations and return ABSOLUTE path
     */
    private function resolvePhotoPath(string $photoPath): string
    {
        // Skip empty
        if (empty($photoPath)) {
            return $photoPath;
        }

        // If it's already an absolute path that exists, return it
        if ($photoPath[0] === '/' && file_exists($photoPath)) {
            return realpath($photoPath);
        }

        // Build candidates — try ABSOLUTE paths only
        $docRoot = $_SERVER['DOCUMENT_ROOT'] ?? '/home/advaysin/public_html';
        $scriptDir = dirname(dirname(dirname(__DIR__)));  // /home/advaysin/public_html/gmind

        $candidates = [];

        if ($photoPath[0] === '/') {
            $candidates[] = $docRoot . $photoPath;
            $candidates[] = $docRoot . '/gmind' . $photoPath;
            $candidates[] = '/home/advaysin/public_html' . $photoPath;
            $candidates[] = '/home/advaysin/public_html/gmind' . $photoPath;
            $candidates[] = $scriptDir . $photoPath;
        } else {
            $candidates[] = $docRoot . '/' . $photoPath;
            $candidates[] = $docRoot . '/gmind/' . $photoPath;
            $candidates[] = '/home/advaysin/public_html/' . $photoPath;
            $candidates[] = '/home/advaysin/public_html/gmind/' . $photoPath;
            $candidates[] = $scriptDir . '/' . $photoPath;
            $candidates[] = $scriptDir . '/public/' . $photoPath;
            $candidates[] = dirname(dirname(dirname(dirname(__DIR__)))) . '/' . $photoPath;
            $candidates[] = dirname(dirname(dirname(dirname(__DIR__)))) . '/gmind/' . $photoPath;
        }

        foreach ($candidates as $c) {
            if (file_exists($c)) {
                return realpath($c);
            }
        }

        if (file_exists($photoPath)) {
            return realpath($photoPath);
        }

        return $photoPath;
    }

    /**
     * Add course duration to a DateTime object.
     * Duration formats: "3 Months", "6 Months", "1 Year", "2 Years", "1.5 Years"
     *
     * IMPORTANT: Duration is INCLUSIVE. So:
     *   "3 Months" → JAN to MAR (3 months total, not JAN to APR)
     *   "1 Year"   → JAN 2025 to DEC 2025 (not JAN 2026)
     *   "6 Months" → JAN to JUN
     *
     * Formula: to_date = from_date + (duration_months - 1)
     */
    private function addDurationToDate(\DateTime $date, string $duration): void
    {
        $duration = trim($duration);
        $monthsToAdd = 0;
        $daysToAdd = 0;

        // Try to parse "X Months"
        if (preg_match('/^([\d.]+)\s*month/i', $duration, $m)) {
            $months = (int)round((float)$m[1]);
            // ✅ FIX: Subtract 1 because duration is inclusive
            // 3 months = JAN + (3-1) = JAN + 2 months = MAR
            $monthsToAdd = max(0, $months - 1);
        }
        // Try to parse "X Years"
        elseif (preg_match('/^([\d.]+)\s*year/i', $duration, $m)) {
            $years = (float)$m[1];
            $totalMonths = (int)round($years * 12);
            // ✅ FIX: Subtract 1 (inclusive)
            // 1 year = 12 months → JAN + 11 months = DEC (same year)
            $monthsToAdd = max(0, $totalMonths - 1);
        }
        // Try to parse "X Days"
        elseif (preg_match('/^([\d.]+)\s*day/i', $duration, $m)) {
            $days = (int)round((float)$m[1]);
            // For days, subtract 1 too (inclusive)
            $daysToAdd = max(0, $days - 1);
        }
        // Try to parse "X Weeks"
        elseif (preg_match('/^([\d.]+)\s*week/i', $duration, $m)) {
            $weeks = (int)round((float)$m[1]);
            $days = $weeks * 7;
            $daysToAdd = max(0, $days - 1);
        }
        else {
            // Unknown format — default to 6 months (inclusive)
            $monthsToAdd = 5;  // 6 - 1
        }

        if ($monthsToAdd > 0) {
            $date->modify("+{$monthsToAdd} months");
        }
        if ($daysToAdd > 0) {
            $date->modify("+{$daysToAdd} days");
        }
    }
}
