<?php
declare(strict_types=1);

/**
 * Upload / replace the Exam Format Profile for a subject × class.
 *
 * A school uploads ONE reference sample (image, PDF, Word doc, or pasted text)
 * of how its exams are set out. The file is extracted, then distilled by AI
 * into a structured format spec in this same request — a one-time cost paid
 * at upload so every later generation reuses the stored spec instead of
 * re-reading the sample. This is a singleton per (subject_id, class_name) —
 * re-uploading archives the previous profile into exam_format_profile_versions
 * rather than losing it.
 */
require_once __DIR__ . '/_json_guard.php';
session_start();
require_once '../../config.php';
require_once dirname(__DIR__) . '/lib/exam_format_profile_schema.php';
require_once dirname(__DIR__) . '/lib/content_chunker.php';
require_once dirname(__DIR__) . '/includes/file_extractor.php';
require_once dirname(__DIR__) . '/lib/exam_format_distiller.php';
header('Content-Type: application/json');

if (!isset($_SESSION['user_id'])) {
    http_response_code(401);
    echo json_encode(['success' => false, 'message' => 'Unauthorized']);
    exit;
}

$conn = getDBConnection();
if (!$conn instanceof mysqli) {
    echo json_encode(['success' => false, 'message' => 'Database connection failed']);
    exit;
}
ensureExamFormatProfileTables($conn);

// ── Plan gate — this belongs to the AI Exam Generator add-on ───────────────
if (!planHasAIExamAddon()) {
    echo json_encode([
        'success' => false,
        'message' => 'AI Exam Generator is not included in your current plan. Please upgrade or contact your administrator.',
    ]);
    exit;
}

$lic  = function_exists('checkLicense') ? checkLicense() : ['plan' => 'starter'];
$plan = $lic['plan'] ?? 'starter';

$maxFileSizeBytes = match ($plan) {
    'premium' => 50 * 1024 * 1024,
    'growth'  => 25 * 1024 * 1024,
    default   => 10 * 1024 * 1024,
};
$maxPages = match ($plan) {
    'premium' => 100,
    'growth'  => 50,
    default   => 20,
};

// ── Basic request validation ────────────────────────────────────────────────
$subjectId  = (int) ($_POST['subject_id'] ?? 0);
$className  = trim((string) ($_POST['class_name'] ?? ''));
$sampleText = trim((string) ($_POST['sample_text'] ?? ''));

if ($subjectId <= 0 || $className === '') {
    echo json_encode(['success' => false, 'message' => 'Subject and class are required']);
    exit;
}

$hasFile = isset($_FILES['file']) && (int) $_FILES['file']['error'] !== UPLOAD_ERR_NO_FILE;
if (!$hasFile && $sampleText === '') {
    echo json_encode(['success' => false, 'message' => 'Upload a sample file or paste sample exam text.']);
    exit;
}

$subjectStmt = $conn->prepare('SELECT subject_name FROM subjects WHERE id = ? LIMIT 1');
$subjectStmt->bind_param('i', $subjectId);
$subjectStmt->execute();
$subjectRow  = $subjectStmt->get_result()->fetch_assoc();
$subjectStmt->close();
$subjectName = (string) ($subjectRow['subject_name'] ?? '');

$sourceType         = 'text';
$originalName       = null;
$storedFilename     = null;
$fileSize           = 0;
$rawContent         = '';
$extractionWarning  = null;

if ($hasFile) {
    $file        = $_FILES['file'];
    $uploadError = (int) $file['error'];
    if ($uploadError !== UPLOAD_ERR_OK) {
        $msg = match ($uploadError) {
            UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE =>
                'File too large (PHP limit: ' . ini_get('upload_max_filesize') . '). '
                . 'Ask your admin to raise upload_max_filesize in php.ini.',
            UPLOAD_ERR_PARTIAL => 'Upload was interrupted — please try again.',
            default            => 'Upload error code ' . $uploadError,
        };
        echo json_encode(['success' => false, 'message' => $msg]);
        exit;
    }

    if ((int) $file['size'] > $maxFileSizeBytes) {
        $limitMB = $maxFileSizeBytes / 1024 / 1024;
        echo json_encode(['success' => false, 'message' => "File exceeds {$limitMB}MB limit for your plan."]);
        exit;
    }

    $ext = strtolower((string) pathinfo((string) $file['name'], PATHINFO_EXTENSION));
    $allowedExtensions = [
        'pdf'  => 'application/pdf',
        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'doc'  => 'application/msword',
        'txt'  => 'text/plain',
        'jpg'  => 'image/jpeg',
        'jpeg' => 'image/jpeg',
        'png'  => 'image/png',
        'webp' => 'image/webp',
    ];
    if (!isset($allowedExtensions[$ext])) {
        echo json_encode([
            'success' => false,
            'message' => "Unsupported file type '.{$ext}'. Allowed: PDF, Word (.docx), TXT, JPG, PNG, WEBP.",
        ]);
        exit;
    }

    $expectedMime = $allowedExtensions[$ext];
    if (function_exists('finfo_open')) {
        $finfo    = finfo_open(FILEINFO_MIME_TYPE);
        $realMime = finfo_file($finfo, (string) $file['tmp_name']);
        finfo_close($finfo);

        if ($realMime === 'application/zip' && $ext === 'docx') {
            $realMime = $expectedMime;
        }

        $safeMimes = [
            'application/pdf',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'application/msword',
            'text/plain',
            'image/jpeg',
            'image/png',
            'image/webp',
            'application/zip',
        ];
        if (!in_array($realMime, $safeMimes, true)) {
            echo json_encode([
                'success' => false,
                'message' => "File content does not match its extension (detected: {$realMime}).",
            ]);
            exit;
        }
        $mimeType = ($realMime === 'application/zip') ? $expectedMime : $realMime;
    } else {
        $mimeType = $expectedMime;
    }

    $formatDir = rtrim(EXAM_UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . 'formats';
    if (!is_dir($formatDir)) {
        @mkdir($formatDir, 0777, true);
    }

    $storedFilename = 'fmt_' . (int) $_SESSION['user_id'] . '_' . time() . '_' . uniqid('', true) . '.' . $ext;
    $targetPath     = $formatDir . DIRECTORY_SEPARATOR . $storedFilename;

    if (!move_uploaded_file((string) $file['tmp_name'], $targetPath)) {
        echo json_encode(['success' => false, 'message' => 'Could not save upload — check server permissions.']);
        exit;
    }

    if ($ext === 'pdf') {
        $pageCount = getPdfPageCount($targetPath);
        if ($pageCount > 0 && $pageCount > $maxPages) {
            @unlink($targetPath);
            echo json_encode([
                'success' => false,
                'message' => "PDF has {$pageCount} pages but your plan allows a maximum of {$maxPages} pages. "
                           . 'Split the document or upgrade your plan.',
            ]);
            exit;
        }
    }

    $sourceType   = match (true) {
        $ext === 'pdf' => 'pdf',
        in_array($ext, ['docx', 'doc'], true) => 'word',
        $ext === 'txt' => 'text',
        default        => 'image',
    };
    $originalName = (string) $file['name'];
    $fileSize     = (int) $file['size'];

    try {
        $extracted = extractTextFromFile($targetPath, $mimeType);
    } catch (Exception $e) {
        $extracted         = '';
        $extractionWarning = $e->getMessage();
        error_log('[EduTrack] Format profile extraction failed: ' . $e->getMessage());
    }

    $rawContent = trim((string) $extracted);
    if ($rawContent !== '') {
        $rawContent = cleanExtractedContent($rawContent);
    }
} else {
    $sourceType = 'text';
    $rawContent = cleanExtractedContent($sampleText);
    $fileSize   = strlen($sampleText);
}

$wordCount = str_word_count($rawContent);

$formatSpecJson = null;
$summaryText    = null;
$distillWarning = null;

if ($rawContent !== '') {
    @set_time_limit(120);
    $distillResult = distillExamFormatProfile($subjectName, $className, $rawContent);
    if (!empty($distillResult['success'])) {
        $formatSpecJson = json_encode($distillResult['format_spec'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        $summaryText    = $distillResult['summary'];
        $status         = 'ready';
        $statusNote     = 'Learned from your sample via ' . ($distillResult['provider'] ?? 'AI') . '.';
    } else {
        $status         = 'failed';
        $distillWarning = (string) ($distillResult['message'] ?? 'AI analysis of the sample failed.');
        $statusNote     = 'Sample saved, but AI analysis of its format failed: ' . $distillWarning . ' Re-upload to retry.';
    }
} else {
    $status     = 'failed';
    $statusNote = $extractionWarning ?: 'No readable text was found in the sample.';
}

// ── Upsert: archive the existing profile (if any), then replace it ─────────
$existingStmt = $conn->prepare('SELECT * FROM exam_format_profiles WHERE subject_id = ? AND class_name = ? LIMIT 1');
$existingStmt->bind_param('is', $subjectId, $className);
$existingStmt->execute();
$existing = $existingStmt->get_result()->fetch_assoc();
$existingStmt->close();

$userId = (int) $_SESSION['user_id'];

if ($existing) {
    $archive = $conn->prepare(
        'INSERT INTO exam_format_profile_versions
            (profile_id, subject_id, class_name, source_type, original_filename, stored_filename,
             raw_extracted_text, format_spec_json, summary_text, status, archived_by)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
    );
    $archive->bind_param(
        'iissssssssi',
        $existing['id'],
        $existing['subject_id'],
        $existing['class_name'],
        $existing['source_type'],
        $existing['original_filename'],
        $existing['stored_filename'],
        $existing['raw_extracted_text'],
        $existing['format_spec_json'],
        $existing['summary_text'],
        $existing['status'],
        $userId
    );
    $archive->execute();
    $archive->close();

    // Remove the superseded file from disk — its text lives on in the version row above.
    if (!empty($existing['stored_filename'])) {
        $oldPath = rtrim(EXAM_UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . 'formats' . DIRECTORY_SEPARATOR . $existing['stored_filename'];
        if (is_file($oldPath)) {
            @unlink($oldPath);
        }
    }

    $update = $conn->prepare(
        'UPDATE exam_format_profiles
         SET subject_name = ?, source_type = ?, original_filename = ?, stored_filename = ?, file_size = ?,
             raw_extracted_text = ?, format_spec_json = ?, summary_text = ?,
             status = ?, status_note = ?, uploaded_by = ?
         WHERE id = ?'
    );
    $update->bind_param(
        'ssssisssssii',
        $subjectName,
        $sourceType,
        $originalName,
        $storedFilename,
        $fileSize,
        $rawContent,
        $formatSpecJson,
        $summaryText,
        $status,
        $statusNote,
        $userId,
        $existing['id']
    );
    $update->execute();
    $update->close();
    $profileId = (int) $existing['id'];
} else {
    $insert = $conn->prepare(
        'INSERT INTO exam_format_profiles
            (subject_id, class_name, subject_name, source_type, original_filename, stored_filename,
             file_size, raw_extracted_text, format_spec_json, summary_text, status, status_note, uploaded_by)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
    );
    $insert->bind_param(
        'isssssisssssi',
        $subjectId,
        $className,
        $subjectName,
        $sourceType,
        $originalName,
        $storedFilename,
        $fileSize,
        $rawContent,
        $formatSpecJson,
        $summaryText,
        $status,
        $statusNote,
        $userId
    );
    $insert->execute();
    $profileId = (int) $insert->insert_id;
    $insert->close();
}

echo json_encode([
    'success'      => $rawContent !== '',
    'profile_id'   => $profileId,
    'source_type'  => $sourceType,
    'filename'     => $originalName,
    'word_count'   => $wordCount,
    'status'       => $status,
    'status_note'  => $statusNote,
    'distilled'    => $status === 'ready',
    'format_spec'  => $formatSpecJson !== null ? json_decode($formatSpecJson, true) : null,
    'summary_text' => $summaryText,
    'warning'      => $distillWarning,
    'preview'      => mb_substr($rawContent, 0, 600),
]);
