<?php

declare(strict_types=1);

/**
 * SuperAdminPatternController
 *
 * Manages Certificate & Marksheet Patterns (Reusable Layouts)
 */

namespace SuperAdmin\Controllers;

use SuperAdmin\Controllers\SuperAdminBaseController;
use App\Helpers\DocumentGenerator;

class SuperAdminPatternController extends SuperAdminBaseController
{
    private function bp(): string
    {
        return defined('BASE_PATH') ? BASE_PATH : '/gmind';
    }

    const FIELD_KEYS = [
        'student_name'   => ['label' => 'Student Name',       'type' => 'text',  'default_font' => 14],
        'father_name'    => ['label' => 'Father Name',        'type' => 'text',  'default_font' => 12],
        'enrollment_no'  => ['label' => 'Enrollment No',      'type' => 'text',  'default_font' => 11],
        'certificate_no' => ['label' => 'Certificate No',     'type' => 'text',  'default_font' => 11],
        'course'         => ['label' => 'Course Name',        'type' => 'text',  'default_font' => 12],
        'branch_name'    => ['label' => 'Branch Name',        'type' => 'text',  'default_font' => 11],
        'branch_code'    => ['label' => 'Branch Code',        'type' => 'text',  'default_font' => 11],
        'duration'       => ['label' => 'Duration',           'type' => 'text',  'default_font' => 11],
        'date_of_issue'  => ['label' => 'Date of Issue',      'type' => 'text',  'default_font' => 11],
        'from_date'      => ['label' => 'From (Month Year)',  'type' => 'text',  'default_font' => 11],
        'to_date'        => ['label' => 'To (Month Year)',    'type' => 'text',  'default_font' => 11],
        'percentage'     => ['label' => 'Percentage',         'type' => 'text',  'default_font' => 12],
        'grade'          => ['label' => 'Grade',              'type' => 'text',  'default_font' => 14],
        'photo'          => ['label' => 'Student Photo',      'type' => 'image', 'default_font' => 0],
        'qr_code'        => ['label' => 'QR Code',            'type' => 'image', 'default_font' => 0],
        'subject_marks'  => ['label' => 'Subject Marks Table','type' => 'table', 'default_font' => 10],
    ];

    public function index(): void
    {
        requireSuperAdmin();

        $sql = "SELECT p.*,
                    (SELECT COUNT(*) FROM `courses` c WHERE c.`cert_pattern_id` = p.`id` OR c.`marksheet_pattern_id` = p.`id`) AS course_count,
                    (SELECT COUNT(*) FROM `certificate_pattern_fields` pf WHERE pf.`pattern_id` = p.`id`) AS field_count
                FROM `certificate_patterns` p
                ORDER BY p.`is_default` DESC, p.`created_at` DESC";
        $stmt = $this->db->query($sql);
        $patterns = $stmt->fetchAll() ?: [];

        $this->superAdminView('patterns/index', [
            'title'       => 'Certificate & Marksheet Patterns',
            'currentPage' => 'patterns',
            'patterns'    => $patterns,
            'csrfToken'   => $this->csrfToken ?? '',
        ]);
    }

    public function create(): void
    {
        requireSuperAdmin();

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $name        = trim($_POST['name'] ?? 'New Pattern');
            $description = trim($_POST['description'] ?? '');

            $sql = "INSERT INTO `certificate_patterns`
                    (`name`, `description`, `page_width`, `page_height`, `status`, `is_default`, `created_by`, `created_at`)
                    VALUES (:name, :desc, 595, 842, 'draft', 0, :uid, NOW())";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([
                ':name' => $name,
                ':desc' => $description,
                ':uid'  => $_SESSION['user_id'] ?? null,
            ]);
            $patternId = (int) $this->db->lastInsertId();

            if ($patternId > 0) {
                $this->seedDefaultFields($patternId, 'certificate');
                $this->seedDefaultFields($patternId, 'marksheet');

                $_SESSION['flash']['success'] = "Pattern '{$name}' created! Now upload backgrounds and map fields.";
                header('Location: ' . $this->bp() . '/super-admin/patterns/edit/' . $patternId);
                exit;
            }
            $_SESSION['flash']['error'] = 'Failed to create pattern.';
        }

        $this->superAdminView('patterns/create', [
            'title'       => 'Create New Pattern',
            'currentPage' => 'patterns',
            'csrfToken'   => $this->csrfToken ?? '',
        ]);
    }

    public function edit(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id) {
            $_SESSION['flash']['error'] = 'Pattern ID required.';
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        if (!$pattern) {
            $_SESSION['flash']['error'] = 'Pattern not found.';
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        // ✅ AUTO-FIX: Ensure ALL fields from FIELD_KEYS exist for this pattern
        // (needed for old patterns created before new fields like branch_code were added)
        $this->ensureAllFieldsExist($id, 'certificate');
        $this->ensureAllFieldsExist($id, 'marksheet');

        // Handle POST: save mapping
        if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($pattern['status'] ?? 'draft') === 'draft') {
            $this->saveMapping($id);

            // ✅ FIX: Check if _then_lock flag is set — if yes, perform lock
            if (isset($_POST['_then_lock']) && $_POST['_then_lock'] == '1') {
                $lockResult = $this->doLock($id);
                if ($lockResult === true) {
                    $_SESSION['flash']['success'] = "Pattern LOCKED successfully! It can now be assigned to courses.";
                    header('Location: ' . $this->bp() . '/super-admin/patterns');
                    exit;
                } else {
                    $_SESSION['flash']['error'] = $lockResult;
                    header('Location: ' . $this->bp() . '/super-admin/patterns/edit/' . $id);
                    exit;
                }
            }

            header('Location: ' . $this->bp() . '/super-admin/patterns/edit/' . $id . '?saved=1');
            exit;
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_pattern_fields` WHERE `pattern_id` = ? AND `doc_type` = 'certificate' ORDER BY `id` ASC");
        $stmt->execute([$id]);
        $certFields = $stmt->fetchAll() ?: [];

        $stmt = $this->db->prepare("SELECT * FROM `certificate_pattern_fields` WHERE `pattern_id` = ? AND `doc_type` = 'marksheet' ORDER BY `id` ASC");
        $stmt->execute([$id]);
        $marksheetFields = $stmt->fetchAll() ?: [];

        $this->superAdminView('patterns/edit', [
            'title'           => 'Edit Pattern: ' . ($pattern['name'] ?? ''),
            'currentPage'     => 'patterns',
            'pattern'         => $pattern,
            'certFields'      => $certFields,
            'marksheetFields' => $marksheetFields,
            'fieldKeys'       => self::FIELD_KEYS,
            'csrfToken'       => $this->csrfToken ?? '',
        ]);
    }

    public function uploadBackground(?int $id = null): void
    {
        requireSuperAdmin();
        header('Content-Type: application/json');

        if (!$id || $_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(400);
            echo json_encode(['error' => 'Invalid request']);
            return;
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        if (!$pattern) {
            http_response_code(404);
            echo json_encode(['error' => 'Pattern not found']);
            return;
        }

        $docType = $_POST['doc_type'] ?? 'certificate';
        if (!in_array($docType, ['certificate', 'marksheet'], true)) {
            http_response_code(400);
            echo json_encode(['error' => 'Invalid doc type']);
            return;
        }

        if (!isset($_FILES['background']) || $_FILES['background']['error'] !== UPLOAD_ERR_OK) {
            http_response_code(400);
            echo json_encode(['error' => 'No file uploaded']);
            return;
        }

        $uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/uploads/patterns/';
        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }

        $ext = strtolower(pathinfo($_FILES['background']['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, ['jpg', 'jpeg', 'png'], true)) {
            http_response_code(400);
            echo json_encode(['error' => 'Only JPG/PNG allowed']);
            return;
        }

        $filename    = 'pattern_' . $id . '_' . $docType . '_' . time() . '.' . $ext;
        $targetPath  = $uploadDir . $filename;

        if (move_uploaded_file($_FILES['background']['tmp_name'], $targetPath)) {
            $dbPath = '/uploads/patterns/' . $filename;
            $column = $docType === 'certificate' ? 'cert_background_path' : 'marksheet_background_path';
            $stmt = $this->db->prepare("UPDATE `certificate_patterns` SET `{$column}` = ? WHERE `id` = ?");
            $stmt->execute([$dbPath, $id]);
            echo json_encode(['success' => true, 'path' => $dbPath, 'url' => $dbPath . '?t=' . time()]);
        } else {
            http_response_code(500);
            echo json_encode(['error' => 'Failed to save file']);
        }
    }

    public function saveMapping(?int $id = null): bool
    {
        if (!$id) {
            return false;
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        if (!$pattern || ($pattern['status'] ?? '') === 'locked') {
            $_SESSION['flash']['error'] = 'Cannot edit locked pattern. Clone it first.';
            return false;
        }

        $stmt = $this->db->prepare("DELETE FROM `certificate_pattern_fields` WHERE `pattern_id` = ?");
        $stmt->execute([$id]);

        $docTypes = ['certificate', 'marksheet'];
        $insertSql = "INSERT INTO `certificate_pattern_fields`
            (`pattern_id`, `doc_type`, `field_key`, `label`, `x_pos`, `y_pos`, `font_size`, `font_style`, `color`, `alignment`, `width`, `height`, `border`, `is_enabled`, `created_at`)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())";
        $stmt = $this->db->prepare($insertSql);

        foreach ($docTypes as $docType) {
            $fieldKeys = $_POST[$docType . '_field_key']  ?? [];
            $xPos      = $_POST[$docType . '_x_pos']       ?? [];
            $yPos      = $_POST[$docType . '_y_pos']       ?? [];
            $fontSize  = $_POST[$docType . '_font_size']   ?? [];
            $fontStyle = $_POST[$docType . '_font_style']  ?? [];
            $color     = $_POST[$docType . '_color']       ?? [];
            $alignment = $_POST[$docType . '_alignment']   ?? [];
            $width     = $_POST[$docType . '_width']       ?? [];
            $height    = $_POST[$docType . '_height']      ?? [];
            $border    = $_POST[$docType . '_border']      ?? [];
            $enabled   = $_POST[$docType . '_is_enabled']  ?? [];

            $count = count($fieldKeys);
            for ($i = 0; $i < $count; $i++) {
                $key = $fieldKeys[$i] ?? '';
                if (empty($key)) continue;

                $label    = self::FIELD_KEYS[$key]['label'] ?? $key;
                $defaultF = self::FIELD_KEYS[$key]['default_font'] ?? 12;

                $stmt->execute([
                    $id, $docType, $key, $label,
                    (float)($xPos[$i] ?? 0),
                    (float)($yPos[$i] ?? 0),
                    (int)($fontSize[$i] ?? $defaultF),
                    $fontStyle[$i] ?? 'regular',
                    $color[$i] ?? '#000000',
                    $alignment[$i] ?? 'L',
                    (float)($width[$i] ?? 0),
                    (float)($height[$i] ?? 0),
                    (int)($border[$i] ?? 0),
                    (int)($enabled[$i] ?? 1),
                ]);
            }
        }

        $stmt = $this->db->prepare("UPDATE `certificate_patterns` SET `updated_at` = NOW() WHERE `id` = ?");
        $stmt->execute([$id]);
        $_SESSION['flash']['success'] = 'Pattern mapping saved!';
        return true;
    }

    public function saveAjax(?int $id = null): void
    {
        requireSuperAdmin();
        header('Content-Type: application/json');

        if (!$id || $_SERVER['REQUEST_METHOD'] !== 'POST') {
            echo json_encode(['error' => 'Invalid request']);
            return;
        }

        $result = $this->saveMapping($id);
        echo json_encode(['success' => $result]);
    }

    public function preview(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id) {
            http_response_code(400);
            echo 'Pattern ID required';
            return;
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        if (!$pattern) {
            http_response_code(404);
            echo 'Pattern not found';
            return;
        }

        $docType = $_GET['doc_type'] ?? 'certificate';

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $this->saveMapping($id);
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        $stmt = $this->db->prepare("SELECT * FROM `certificate_pattern_fields` WHERE `pattern_id` = ? AND `doc_type` = ? AND `is_enabled` = 1 ORDER BY `id` ASC");
        $stmt->execute([$id, $docType]);
        $fields = $stmt->fetchAll() ?: [];

        $sampleData = [
            'student_name'   => 'Rahul Kumar Sharma',
            'father_name'    => 'Suresh Kumar Sharma',
            'enrollment_no'  => 'GM2025001',
            'certificate_no' => 'CERT-2025-0001',
            'course'         => 'Diploma in Computer Application',
            'branch_name'    => 'Main Branch, Lucknow',
            'branch_code'    => 'GMBR01',
            'duration'       => '6 Months',
            'date_of_issue'  => date('d/m/Y'),
            'from_date'      => 'January 2025',
            'to_date'        => 'June 2025',
            'percentage'     => '85.5%',
            'grade'          => 'A+',
            'photo'          => '',
            'qr_data'        => 'PREVIEW-' . $id . '-' . $docType,
            'subjects' => [
                ['name' => 'Fundamentals of Computer', 'max' => 100, 'obtained' => 88, 'grade' => 'A+'],
                ['name' => 'MS Office',                'max' => 100, 'obtained' => 92, 'grade' => 'A++'],
                ['name' => 'Internet & HTML',          'max' => 100, 'obtained' => 78, 'grade' => 'A'],
                ['name' => 'Tally ERP',                'max' => 100, 'obtained' => 85, 'grade' => 'A+'],
                ['name' => 'Photoshop',                'max' => 100, 'obtained' => 80, 'grade' => 'A'],
                ['name' => 'Programming in C',         'max' => 100, 'obtained' => 90, 'grade' => 'A++'],
                ['name' => 'Practical Lab',            'max' => 100, 'obtained' => 95, 'grade' => 'S'],
            ],
        ];

        $bgPath = $docType === 'certificate'
            ? ($pattern['cert_background_path'] ?? '')
            : ($pattern['marksheet_background_path'] ?? '');

        $fullBgPath = $_SERVER['DOCUMENT_ROOT'] . $bgPath;
        if (empty($bgPath) || !file_exists($fullBgPath)) {
            echo "Background image not uploaded. Please upload JPG for {$docType} first.<br>";
            echo "Expected path: " . htmlspecialchars($fullBgPath);
            return;
        }

        try {
            $generator = new DocumentGenerator();
            $pdf = $generator->generateFromPattern([
                'pattern'    => $pattern,
                'fields'     => $fields,
                'student'    => $sampleData,
                'doc_type'   => $docType,
                'bg_path'    => $fullBgPath,
                'is_preview' => true,
            ]);
            $pdf->Output('I', 'preview_' . $docType . '.pdf');
        } catch (\Throwable $e) {
            http_response_code(500);
            echo 'PDF generation failed: ' . htmlspecialchars($e->getMessage());
        }
    }

    /**
     * Internal lock logic — returns true on success, error string on failure
     */
    private function doLock(int $id)
    {
        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        if (!$pattern) {
            return 'Pattern not found.';
        }

        if (empty($pattern['cert_background_path']) || empty($pattern['marksheet_background_path'])) {
            return 'Cannot lock: Please upload BOTH certificate AND marksheet background images first.';
        }

        $stmt = $this->db->prepare("SELECT COUNT(*) as cnt FROM `certificate_pattern_fields` WHERE `pattern_id` = ? AND `doc_type` = 'certificate' AND `is_enabled` = 1");
        $stmt->execute([$id]);
        $certCount = $stmt->fetch();

        $stmt = $this->db->prepare("SELECT COUNT(*) as cnt FROM `certificate_pattern_fields` WHERE `pattern_id` = ? AND `doc_type` = 'marksheet' AND `is_enabled` = 1");
        $stmt->execute([$id]);
        $marksheetCount = $stmt->fetch();

        if (($certCount['cnt'] ?? 0) == 0 || ($marksheetCount['cnt'] ?? 0) == 0) {
            return 'Cannot lock: Map at least one field for both certificate AND marksheet.';
        }

        $stmt = $this->db->prepare("UPDATE `certificate_patterns` SET `status` = 'locked', `locked_at` = NOW() WHERE `id` = ?");
        $stmt->execute([$id]);

        return true;
    }

    public function lock(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id) {
            $_SESSION['flash']['error'] = 'Pattern ID required.';
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $result = $this->doLock($id);

        if ($result === true) {
            $stmt = $this->db->prepare("SELECT `name` FROM `certificate_patterns` WHERE `id` = ?");
            $stmt->execute([$id]);
            $pattern = $stmt->fetch();
            $_SESSION['flash']['success'] = "Pattern '" . ($pattern['name'] ?? '') . "' LOCKED! It can now be assigned to courses.";
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        } else {
            $_SESSION['flash']['error'] = $result;
            header('Location: ' . $this->bp() . '/super-admin/patterns/edit/' . $id);
            exit;
        }
    }

    public function unlock(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id) {
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $stmt = $this->db->prepare("UPDATE `certificate_patterns` SET `status` = 'draft', `locked_at` = NULL WHERE `id` = ?");
        $stmt->execute([$id]);

        $_SESSION['flash']['success'] = 'Pattern unlocked. You can edit it now.';
        header('Location: ' . $this->bp() . '/super-admin/patterns');
        exit;
    }

    public function clone(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id) {
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        if (!$pattern) {
            $_SESSION['flash']['error'] = 'Pattern not found.';
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $countStmt = $this->db->query("SELECT COUNT(*) as cnt FROM `certificate_patterns`");
        $countRow  = $countStmt->fetch();
        $nextNum   = ((int)($countRow['cnt'] ?? 0)) + 1;

        $sql = "INSERT INTO `certificate_patterns`
                (`name`, `description`, `cert_background_path`, `marksheet_background_path`,
                 `page_width`, `page_height`, `status`, `is_default`, `created_by`, `created_at`)
                VALUES (:name, :desc, :cbp, :mbp, :pw, :ph, 'draft', 0, :uid, NOW())";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([
            ':name' => 'Pattern ' . $nextNum . ' (Cloned from ' . $pattern['name'] . ')',
            ':desc' => $pattern['description'],
            ':cbp'  => $pattern['cert_background_path'],
            ':mbp'  => $pattern['marksheet_background_path'],
            ':pw'   => $pattern['page_width'],
            ':ph'   => $pattern['page_height'],
            ':uid'  => $_SESSION['user_id'] ?? null,
        ]);
        $newId = (int) $this->db->lastInsertId();

        $stmt = $this->db->prepare("SELECT * FROM `certificate_pattern_fields` WHERE `pattern_id` = ?");
        $stmt->execute([$id]);
        $fields = $stmt->fetchAll() ?: [];

        $copySql = "INSERT INTO `certificate_pattern_fields`
            (`pattern_id`, `doc_type`, `field_key`, `label`, `x_pos`, `y_pos`, `font_size`, `font_style`, `color`, `alignment`, `width`, `height`, `border`, `is_enabled`, `created_at`)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())";
        $copyStmt = $this->db->prepare($copySql);

        foreach ($fields as $f) {
            $copyStmt->execute([
                $newId, $f['doc_type'], $f['field_key'], $f['label'],
                $f['x_pos'], $f['y_pos'], $f['font_size'], $f['font_style'],
                $f['color'], $f['alignment'], $f['width'], $f['height'],
                $f['border'], $f['is_enabled'],
            ]);
        }

        $_SESSION['flash']['success'] = 'Pattern cloned! New draft created - edit and lock it.';
        header('Location: ' . $this->bp() . '/super-admin/patterns/edit/' . $newId);
        exit;
    }

    public function setDefault(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id) {
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $this->db->query("UPDATE `certificate_patterns` SET `is_default` = 0");
        $stmt = $this->db->prepare("UPDATE `certificate_patterns` SET `is_default` = 1 WHERE `id` = ?");
        $stmt->execute([$id]);

        $_SESSION['flash']['success'] = 'Default pattern updated.';
        header('Location: ' . $this->bp() . '/super-admin/patterns');
        exit;
    }

    public function delete(?int $id = null): void
    {
        requireSuperAdmin();

        if (!$id) {
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $stmt = $this->db->prepare("SELECT * FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);
        $pattern = $stmt->fetch();

        if (!$pattern) {
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        if ($pattern['status'] === 'locked') {
            $_SESSION['flash']['error'] = 'Cannot delete locked pattern. Unlock first or use clone.';
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $stmt = $this->db->prepare("SELECT COUNT(*) as cnt FROM `courses` WHERE `cert_pattern_id` = ? OR `marksheet_pattern_id` = ?");
        $stmt->execute([$id, $id]);
        $usage = $stmt->fetch();

        if (($usage['cnt'] ?? 0) > 0) {
            $_SESSION['flash']['error'] = 'Cannot delete: Pattern is assigned to ' . $usage['cnt'] . ' course(s). Unassign first.';
            header('Location: ' . $this->bp() . '/super-admin/patterns');
            exit;
        }

        $stmt = $this->db->prepare("DELETE FROM `certificate_pattern_fields` WHERE `pattern_id` = ?");
        $stmt->execute([$id]);

        $stmt = $this->db->prepare("DELETE FROM `certificate_patterns` WHERE `id` = ?");
        $stmt->execute([$id]);

        $_SESSION['flash']['success'] = 'Pattern deleted.';
        header('Location: ' . $this->bp() . '/super-admin/patterns');
        exit;
    }

    public function uploadTestPhoto(): void
    {
        requireSuperAdmin();
        header('Content-Type: application/json');

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            echo json_encode(['error' => 'Invalid request']);
            return;
        }

        if (session_status() === PHP_SESSION_NONE) {
            if (defined('SESSION_NAME')) {
                session_name(SESSION_NAME);
            }
            session_start();
        }

        if (!isset($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
            echo json_encode(['error' => 'No photo uploaded (error code: ' . ($_FILES['photo']['error'] ?? 'unknown') . ')']);
            return;
        }

        $ext = strtolower(pathinfo($_FILES['photo']['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, ['jpg', 'jpeg', 'png'], true)) {
            echo json_encode(['error' => 'Only JPG/PNG allowed']);
            return;
        }

        $tempPath = sys_get_temp_dir() . '/pattern_test_photo_' . session_id() . '.jpg';
        if (move_uploaded_file($_FILES['photo']['tmp_name'], $tempPath)) {
            $_SESSION['test_photo_path'] = $tempPath;
            echo json_encode(['success' => true, 'message' => 'Test photo uploaded.']);
        } else {
            echo json_encode(['error' => 'Failed to save photo.']);
        }
    }

    public function clearTestPhoto(): void
    {
        requireSuperAdmin();
        header('Content-Type: application/json');

        if (session_status() === PHP_SESSION_NONE) {
            if (defined('SESSION_NAME')) {
                session_name(SESSION_NAME);
            }
            session_start();
        }

        if (!empty($_SESSION['test_photo_path']) && file_exists($_SESSION['test_photo_path'])) {
            unlink($_SESSION['test_photo_path']);
        }
        unset($_SESSION['test_photo_path']);
        echo json_encode(['success' => true]);
    }

    public function assignToCourse(): void
    {
        requireSuperAdmin();
        header('Content-Type: application/json');

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            echo json_encode(['error' => 'Invalid request']);
            return;
        }

        $courseId  = (int)($_POST['course_id'] ?? 0);
        $patternId = (int)($_POST['pattern_id'] ?? 0);
        $docType   = $_POST['doc_type'] ?? 'certificate';

        if (!$courseId || !$patternId) {
            echo json_encode(['error' => 'Missing parameters']);
            return;
        }

        $col = $docType === 'certificate' ? 'cert_pattern_id' : 'marksheet_pattern_id';
        $stmt = $this->db->prepare("UPDATE `courses` SET `{$col}` = ? WHERE `id` = ?");
        $stmt->execute([$patternId, $courseId]);

        echo json_encode(['success' => true]);
    }

    public static function getLockedPatterns(): array
    {
        try {
            $configFile = dirname(dirname(dirname(__DIR__))) . '/config/database.php';
            if (!file_exists($configFile)) return [];

            // Use require_once with output buffering to extract constants
            if (!defined('DB_HOST')) {
                require_once $configFile;
            }

            if (!defined('DB_HOST')) return [];

            $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4";
            $pdo = new \PDO($dsn, DB_USER, DB_PASS ?? '', [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
            ]);

            $stmt = $pdo->query("SELECT `id`, `name`, `is_default` FROM `certificate_patterns` WHERE `status` = 'locked' ORDER BY `is_default` DESC, `name` ASC");
            return $stmt->fetchAll() ?: [];
        } catch (\Throwable $e) {
            return [];
        }
    }

    /**
     * ✅ AUTO-FIX: Ensure all fields from FIELD_KEYS exist for a pattern+doc_type
     * If a field is missing (e.g., branch_code added later), insert it with defaults.
     * Also ensures branch_code is ALWAYS enabled on both doc types.
     */
    private function ensureAllFieldsExist(int $patternId, string $docType): void
    {
        $stmt = $this->db->prepare("SELECT field_key, is_enabled FROM `certificate_pattern_fields` WHERE `pattern_id` = ? AND `doc_type` = ?");
        $stmt->execute([$patternId, $docType]);
        $existingRows = $stmt->fetchAll() ?: [];
        $existingKeys = array_column($existingRows, 'field_key');

        // Default positions for each field
        $defaults = [
            'student_name'   => ['x' => 297, 'y' => 250, 'fs' => 18, 'align' => 'C'],
            'father_name'    => ['x' => 297, 'y' => 290, 'fs' => 12, 'align' => 'C'],
            'enrollment_no'  => ['x' => 100, 'y' => 350, 'fs' => 11, 'align' => 'L'],
            'certificate_no' => ['x' => 450, 'y' => 350, 'fs' => 11, 'align' => 'R'],
            'course'         => ['x' => 297, 'y' => 400, 'fs' => 14, 'align' => 'C'],
            'branch_name'    => ['x' => 297, 'y' => 430, 'fs' => 11, 'align' => 'C'],
            'branch_code'    => ['x' => 297, 'y' => 455, 'fs' => 11, 'align' => 'C'],
            'duration'       => ['x' => 297, 'y' => 460, 'fs' => 11, 'align' => 'C'],
            'date_of_issue'  => ['x' => 297, 'y' => 600, 'fs' => 11, 'align' => 'C'],
            'from_date'      => ['x' => 180, 'y' => 520, 'fs' => 11, 'align' => 'C'],
            'to_date'        => ['x' => 410, 'y' => 520, 'fs' => 11, 'align' => 'C'],
            'percentage'     => ['x' => 297, 'y' => 500, 'fs' => 14, 'align' => 'C'],
            'grade'          => ['x' => 297, 'y' => 530, 'fs' => 16, 'align' => 'C'],
            'photo'          => ['x' => 60,  'y' => 200, 'fs' => 0,  'align' => 'L', 'w' => 35, 'h' => 45],
            'qr_code'        => ['x' => 510, 'y' => 760, 'fs' => 0,  'align' => 'L', 'w' => 30, 'h' => 30],
            'subject_marks'  => ['x' => 80,  'y' => 480, 'fs' => 10, 'align' => 'L', 'w' => 435, 'h' => 0],
        ];

        if ($docType === 'marksheet') {
            $defaults['subject_marks'] = ['x' => 80, 'y' => 400, 'fs' => 10, 'align' => 'L', 'w' => 435, 'h' => 0];
            $defaults['percentage']    = ['x' => 297, 'y' => 720, 'fs' => 14, 'align' => 'C'];
            $defaults['grade']         = ['x' => 297, 'y' => 750, 'fs' => 16, 'align' => 'C'];
            $defaults['branch_code']   = ['x' => 480, 'y' => 100, 'fs' => 11, 'align' => 'R'];
        }

        // Insert missing fields
        $insertSql = "INSERT INTO `certificate_pattern_fields`
            (`pattern_id`, `doc_type`, `field_key`, `label`, `x_pos`, `y_pos`, `font_size`, `font_style`, `color`, `alignment`, `width`, `height`, `border`, `is_enabled`, `created_at`)
            VALUES (?, ?, ?, ?, ?, ?, ?, 'regular', '#000000', ?, ?, ?, ?, ?, NOW())";
        $insertStmt = $this->db->prepare($insertSql);

        foreach (self::FIELD_KEYS as $key => $meta) {
            if (!in_array($key, $existingKeys)) {
                $d = $defaults[$key] ?? ['x' => 100, 'y' => 100, 'fs' => $meta['default_font'], 'align' => 'L'];
                $border = ($key === 'photo' || $key === 'subject_marks') ? 1 : 0;

                $isEnabled = 1;
                if ($docType === 'certificate' && in_array($key, ['subject_marks', 'duration', 'from_date', 'to_date', 'percentage'])) {
                    $isEnabled = 0;
                }
                if ($docType === 'marksheet' && in_array($key, ['from_date', 'to_date'])) {
                    $isEnabled = 0;
                }
                // ✅ branch_code ALWAYS enabled
                if ($key === 'branch_code') {
                    $isEnabled = 1;
                }

                $insertStmt->execute([
                    $patternId, $docType, $key, $meta['label'],
                    $d['x'], $d['y'], $d['fs'], $d['align'],
                    $d['w'] ?? 0, $d['h'] ?? 0, $border, $isEnabled,
                ]);
            }
        }

        // ✅ Ensure branch_code is ENABLED and has correct position (force fix existing)
        $forceUpdateSql = "UPDATE `certificate_pattern_fields`
            SET `is_enabled` = 1, `x_pos` = ?, `y_pos` = ?, `alignment` = ?
            WHERE `pattern_id` = ? AND `doc_type` = ? AND `field_key` = 'branch_code'";
        $forceStmt = $this->db->prepare($forceUpdateSql);

        if ($docType === 'marksheet') {
            $forceStmt->execute([480, 100, 'R', $patternId, $docType]);  // top-right
        } else {
            $forceStmt->execute([297, 455, 'C', $patternId, $docType]);  // center
        }
    }

    private function seedDefaultFields(int $patternId, string $docType): void
    {
        $defaults = [
            'student_name'   => ['x' => 297, 'y' => 250, 'fs' => 18, 'align' => 'C'],
            'father_name'    => ['x' => 297, 'y' => 290, 'fs' => 12, 'align' => 'C'],
            'enrollment_no'  => ['x' => 100, 'y' => 350, 'fs' => 11, 'align' => 'L'],
            'certificate_no' => ['x' => 450, 'y' => 350, 'fs' => 11, 'align' => 'R'],
            'course'         => ['x' => 297, 'y' => 400, 'fs' => 14, 'align' => 'C'],
            'branch_name'    => ['x' => 297, 'y' => 430, 'fs' => 11, 'align' => 'C'],
            'branch_code'    => ['x' => 297, 'y' => 455, 'fs' => 11, 'align' => 'C'],
            'duration'       => ['x' => 297, 'y' => 460, 'fs' => 11, 'align' => 'C'],
            'date_of_issue'  => ['x' => 297, 'y' => 600, 'fs' => 11, 'align' => 'C'],
            'from_date'      => ['x' => 180, 'y' => 520, 'fs' => 11, 'align' => 'C'],
            'to_date'        => ['x' => 410, 'y' => 520, 'fs' => 11, 'align' => 'C'],
            'percentage'     => ['x' => 297, 'y' => 500, 'fs' => 14, 'align' => 'C'],
            'grade'          => ['x' => 297, 'y' => 530, 'fs' => 16, 'align' => 'C'],
            'photo'          => ['x' => 60,  'y' => 200, 'fs' => 0,  'align' => 'L', 'w' => 35, 'h' => 45],
            'qr_code'        => ['x' => 510, 'y' => 760, 'fs' => 0,  'align' => 'L', 'w' => 30, 'h' => 30],
            'subject_marks'  => ['x' => 80,  'y' => 480, 'fs' => 10, 'align' => 'L', 'w' => 435, 'h' => 0],
        ];

        if ($docType === 'marksheet') {
            $defaults['subject_marks'] = ['x' => 80, 'y' => 400, 'fs' => 10, 'align' => 'L', 'w' => 435, 'h' => 0];
            $defaults['percentage']    = ['x' => 297, 'y' => 720, 'fs' => 14, 'align' => 'C'];
            $defaults['grade']         = ['x' => 297, 'y' => 750, 'fs' => 16, 'align' => 'C'];
            // Branch code repositioned on marksheet (top-right corner)
            $defaults['branch_code']   = ['x' => 480, 'y' => 100, 'fs' => 11, 'align' => 'R'];
        }

        $sql = "INSERT INTO `certificate_pattern_fields`
            (`pattern_id`, `doc_type`, `field_key`, `label`, `x_pos`, `y_pos`, `font_size`, `font_style`, `color`, `alignment`, `width`, `height`, `border`, `is_enabled`, `created_at`)
            VALUES (?, ?, ?, ?, ?, ?, ?, 'regular', '#000000', ?, ?, ?, ?, ?, NOW())";
        $stmt = $this->db->prepare($sql);

        foreach (self::FIELD_KEYS as $key => $meta) {
            $d = $defaults[$key] ?? ['x' => 100, 'y' => 100, 'fs' => $meta['default_font'], 'align' => 'L'];
            $border = ($key === 'photo' || $key === 'subject_marks') ? 1 : 0;

            $isEnabled = 1;
            // Certificate: disable fields not relevant to certificate
            if ($docType === 'certificate' && in_array($key, ['subject_marks', 'duration', 'from_date', 'to_date', 'percentage'])) {
                $isEnabled = 0;
            }
            // ✅ Marksheet: disable from_date and to_date (these are certificate-only)
            if ($docType === 'marksheet' && in_array($key, ['from_date', 'to_date'])) {
                $isEnabled = 0;
            }

            $stmt->execute([
                $patternId, $docType, $key, $meta['label'],
                $d['x'], $d['y'], $d['fs'], $d['align'],
                $d['w'] ?? 0, $d['h'] ?? 0, $border, $isEnabled,
            ]);
        }
    }
}
