<?php
/**
 * Preservation Verification Tests — resolveCurrentSessionTerm() Returns Same Values as Original
 *
 * Validates: Requirements 3.1, 3.2, 3.3
 *
 * Property 2: Preservation (Fixed Code)
 *
 * PURPOSE: Verify that for active dates (isBugCondition(today) = false),
 * resolveCurrentSessionTerm($con) returns the same session_id, session_name,
 * term_id, and term_name as the original inline primary queries.
 *
 * This is a companion to test_gap_preservation.php — it tests the FIXED helper
 * rather than the original inline queries.
 *
 * EXPECTED OUTCOME: All tests PASS — confirms no regressions on active-date paths.
 *
 * Run via CLI: php portal/tests/test_gap_preservation_fixed.php
 */

// ── Bootstrap ────────────────────────────────────────────────────────────────
$root = dirname(__DIR__); // portal/
require_once "{$root}/includes/dbconnection.php";
require_once "{$root}/includes/session_term_helper.php";

if (!isset($con) || mysqli_connect_errno()) {
    echo "FATAL: Could not connect to database.\n";
    exit(1);
}

// ── Helpers ──────────────────────────────────────────────────────────────────
$pass = 0;
$fail = 0;

function assert_test(string $label, bool $condition, string $detail = ''): void
{
    global $pass, $fail;
    if ($condition) {
        echo "[PASS] $label\n";
        $pass++;
    } else {
        echo "[FAIL] $label\n";
        if ($detail !== '') {
            echo "       Detail: $detail\n";
        }
        $fail++;
    }
}

// ── Show current date for context ─────────────────────────────────────────────
$dateRow = $con->query("SELECT CURDATE() AS today")->fetch_assoc();
echo "\n=== Preservation Verification Tests: resolveCurrentSessionTerm() vs Original Primary Query ===\n";
echo "MySQL CURDATE() = {$dateRow['today']}\n\n";
echo "Validates: Requirements 3.1, 3.2, 3.3\n\n";

// ── Setup: insert a CURRENTLY ACTIVE session and term ────────────────────────
// start_date = CURDATE()-15, end_date = CURDATE()+15 → today is mid-term (active)
// isBugCondition(today) = false for this row — the primary query WILL find it.
$ts = time();
$sessionName = "TEST_PRES_FIXED_{$ts}";
$termName = 'First Term'; // valid enum value

// Clean up any leftover rows from a previous run
$con->query("DELETE st FROM school_terms st
             INNER JOIN school_sessions ss ON st.session_id = ss.id
             WHERE ss.session_name = '$sessionName'");
$con->query("DELETE FROM school_sessions WHERE session_name = '$sessionName'");

// Insert session: started 15 days ago, ends 15 days from now — ACTIVE today
$insertSession = $con->prepare(
    "INSERT INTO school_sessions (session_name, start_date, end_date)
     VALUES (?, DATE_SUB(CURDATE(), INTERVAL 15 DAY), DATE_ADD(CURDATE(), INTERVAL 15 DAY))"
);
if (!$insertSession) {
    echo "FATAL: Could not prepare session insert: {$con->error}\n";
    exit(1);
}
$insertSession->bind_param('s', $sessionName);
$insertSession->execute();
$sessionId = $con->insert_id;
$insertSession->close();

if (!$sessionId) {
    echo "FATAL: Failed to insert test session row.\n";
    exit(1);
}

// Insert term linked to that session with the same active date range
$insertTerm = $con->prepare(
    "INSERT INTO school_terms (term_name, session_id, start_date, end_date)
     VALUES (?, ?, DATE_SUB(CURDATE(), INTERVAL 15 DAY), DATE_ADD(CURDATE(), INTERVAL 15 DAY))"
);
if (!$insertTerm) {
    echo "FATAL: Could not prepare term insert: {$con->error}\n";
    exit(1);
}
$insertTerm->bind_param('si', $termName, $sessionId);
$insertTerm->execute();
$termId = $con->insert_id;
$insertTerm->close();

if (!$termId) {
    echo "FATAL: Failed to insert test term row.\n";
    exit(1);
}

echo "Test session inserted: id=$sessionId, session_name='$sessionName'\n";
echo "Test term inserted:    id=$termId,    term_name='$termName'\n";
echo "Both rows: start_date = CURDATE()-15, end_date = CURDATE()+15\n";
echo "Today is MID-TERM — the session and term are ACTIVE.\n";
echo "isBugCondition(today) = false for this scenario.\n\n";

// ── Call resolveCurrentSessionTerm() from the helper ─────────────────────────
$st = resolveCurrentSessionTerm($con);

// The helper returns the first active session by start_date ASC.
// Our test session is active, so it should be returned (or another active session
// with an earlier start_date may be returned if one exists in the DB).
// To isolate our test row, we verify the helper returns AN active session,
// then cross-check against the original primary query scoped to our inserted session.

// ── Run the ORIGINAL inline primary session query (scoped to our test session) ─
$primarySessionQuery = "SELECT id, session_name FROM school_sessions
                        WHERE id = ?
                        AND start_date <= CURDATE() AND end_date >= CURDATE()
                        ORDER BY start_date ASC LIMIT 1";
$stmtSession = $con->prepare($primarySessionQuery);
$stmtSession->bind_param('i', $sessionId);
$stmtSession->execute();
$sessionResult = $stmtSession->get_result();
$sessionRow = ($sessionResult && $sessionResult->num_rows > 0)
    ? $sessionResult->fetch_assoc()
    : null;
$stmtSession->close();

$origSessionId = $sessionRow ? (int) $sessionRow['id'] : 0;
$origSessionName = $sessionRow ? $sessionRow['session_name'] : null;

// ── Run the ORIGINAL inline primary term query (scoped to our test term) ──────
$origTermId = 0;
$origTermName = null;

if ($origSessionName !== null) {
    $primaryTermQuery = "SELECT id, term_name FROM school_terms
                         WHERE session_id = ? AND id = ?
                         AND start_date <= CURDATE() AND end_date >= CURDATE()
                         ORDER BY start_date ASC LIMIT 1";
    $stmtTerm = $con->prepare($primaryTermQuery);
    $stmtTerm->bind_param('ii', $origSessionId, $termId);
    $stmtTerm->execute();
    $termResult = $stmtTerm->get_result();
    $termRow = ($termResult && $termResult->num_rows > 0)
        ? $termResult->fetch_assoc()
        : null;
    $stmtTerm->close();

    if ($termRow !== null) {
        $origTermId = (int) $termRow['id'];
        $origTermName = $termRow['term_name'];
    }
}

echo "Original primary query results (scoped to test rows):\n";
echo "  session_id=$origSessionId, session_name=" . var_export($origSessionName, true) . "\n";
echo "  term_id=$origTermId, term_name=" . var_export($origTermName, true) . "\n\n";

echo "resolveCurrentSessionTerm() results:\n";
echo "  session_id={$st['session_id']}, session_name=" . var_export($st['session_name'], true) . "\n";
echo "  term_id={$st['term_id']}, term_name=" . var_export($st['term_name'], true) . "\n\n";

// ── Assertions ────────────────────────────────────────────────────────────────

// Test 1: resolveCurrentSessionTerm returns a non-null session_name (Requirement 3.1)
assert_test(
    "resolveCurrentSessionTerm() returns non-null session_name for active date (Requirement 3.1)",
    $st['session_name'] !== null,
    "Expected non-null session_name. Got: " . var_export($st['session_name'], true)
);

// Test 2: resolveCurrentSessionTerm returns a non-null term_name (Requirement 3.2)
assert_test(
    "resolveCurrentSessionTerm() returns non-null term_name for active date (Requirement 3.2)",
    $st['term_name'] !== null,
    "Expected non-null term_name. Got: " . var_export($st['term_name'], true)
);

// Test 3: session_id matches the inserted active session (Requirement 3.1)
// The helper returns the first active session by start_date ASC — our test session is active.
// We verify the returned session_id is our inserted session (or another active one if it has
// an earlier start_date, in which case we verify our session is also active via the scoped query).
$helperReturnedOurSession = ($st['session_id'] === $sessionId);
$helperReturnedActiveSession = ($st['session_id'] > 0 && $st['session_name'] !== null);
assert_test(
    "resolveCurrentSessionTerm() returns an active session_id (Requirement 3.1)",
    $helperReturnedActiveSession,
    "Expected active session_id > 0. Got: session_id={$st['session_id']}"
);

// Test 4: session_name matches the inserted active session (Requirement 3.1)
// If the helper returned our specific test session, verify the name matches exactly.
if ($helperReturnedOurSession) {
    assert_test(
        "session_name matches inserted test session (Requirement 3.1)",
        $st['session_name'] === $sessionName,
        "Expected session_name='$sessionName', got: " . var_export($st['session_name'], true)
    );
} else {
    // Another active session with an earlier start_date was returned — that is correct behavior.
    // Verify our test session IS active via the scoped original query.
    assert_test(
        "Original primary query confirms test session is active (Requirement 3.1)",
        $origSessionId === $sessionId && $origSessionName === $sessionName,
        "Expected scoped query to find session_id=$sessionId, session_name='$sessionName'. " .
        "Got: session_id=$origSessionId, session_name=" . var_export($origSessionName, true)
    );
}

// Test 5: term_id matches the inserted active term (Requirement 3.2)
$helperReturnedOurTerm = ($st['term_id'] === $termId);
$helperReturnedActiveTerm = ($st['term_id'] > 0 && $st['term_name'] !== null);
assert_test(
    "resolveCurrentSessionTerm() returns an active term_id (Requirement 3.2)",
    $helperReturnedActiveTerm,
    "Expected active term_id > 0. Got: term_id={$st['term_id']}"
);

// Test 6: term_name matches the inserted active term (Requirement 3.2)
if ($helperReturnedOurSession && $helperReturnedOurTerm) {
    assert_test(
        "term_name matches inserted test term (Requirement 3.2)",
        $st['term_name'] === $termName,
        "Expected term_name='$termName', got: " . var_export($st['term_name'], true)
    );
} else {
    // Another session/term was returned — verify our test term is active via scoped query.
    assert_test(
        "Original primary query confirms test term is active (Requirement 3.2)",
        $origTermId === $termId && $origTermName === $termName,
        "Expected scoped query to find term_id=$termId, term_name='$termName'. " .
        "Got: term_id=$origTermId, term_name=" . var_export($origTermName, true)
    );
}

// Test 7: Primary query path was used (not fallback) — active session returned (Requirement 3.3)
// On an active date, the helper must use the primary query path.
// We verify this by confirming the returned session has end_date >= CURDATE() (i.e., still active).
$activeCheckStmt = $con->prepare(
    "SELECT COUNT(*) AS cnt FROM school_sessions
     WHERE id = ? AND start_date <= CURDATE() AND end_date >= CURDATE()"
);
$activeCheckStmt->bind_param('i', $st['session_id']);
$activeCheckStmt->execute();
$activeCheckRow = $activeCheckStmt->get_result()->fetch_assoc();
$activeCheckStmt->close();

$returnedSessionIsActive = ((int) $activeCheckRow['cnt']) > 0;
assert_test(
    "Primary query path used — returned session is currently active, not a past one (Requirement 3.3)",
    $returnedSessionIsActive,
    "Expected returned session_id={$st['session_id']} to be active (start_date <= CURDATE() <= end_date). " .
    "A past session would indicate the fallback path was incorrectly used."
);

// ── Cleanup ───────────────────────────────────────────────────────────────────
$con->query("DELETE FROM school_terms WHERE id = $termId");
$con->query("DELETE FROM school_sessions WHERE id = $sessionId");
echo "\nTest rows cleaned up.\n";

// ── Summary ───────────────────────────────────────────────────────────────────
echo "\n=== Results: $pass passed, $fail failed ===\n";

if ($fail > 0) {
    echo "\nFAIL — Preservation regression detected: resolveCurrentSessionTerm() did not return expected values.\n";
    echo "The fix may have broken active-date behavior.\n";
    exit(1);
} else {
    echo "\nPASS — All preservation assertions passed.\n";
    echo "resolveCurrentSessionTerm() correctly uses the primary query path for active dates.\n";
    echo "No regressions detected — active-date behavior is preserved after the fix.\n";
    exit(0);
}
