<?php
// =============================================================
//  POST /api/v1/assessments/student_submit
//
//  Submits a Clinical Student assessment — mirrors
//  app/clinical_assessment_form.php's INSERT path (single-stage, unlike
//  the nurse pipeline). Insert-only: the pending list already excludes
//  any student+unit+rotation combo with an existing clinical_assessments
//  row of ANY status (including 'draft'), matching the web page's own
//  eligibility query exactly, so there is no reachable "update a draft"
//  case here to replicate — which is also the exact path that was found
//  to crash outright in the web app (see the separate commit fixing
//  clinical_assessment_form.php's bind_param call).
//
//  Body: {
//    "student_id": 2, "rotation_id": 3, "unit_id": 5,
//    "scores": { "a1_history_physical": 5, ... }, "comments": "optional"
//  }
//
//  Scoring rule (matches the web form exactly): a criterion left at 0 is
//  NOT counted toward max_possible — it's treated as "not rated", not as
//  a rock-bottom score. Only criteria scored 1-5 count toward both the
//  total and the max.
// =============================================================

require_once __DIR__ . '/../_bootstrap.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    Api::error(405, 'MethodNotAllowed', 'Use POST');
}

$account = api_authenticate();
api_require_permission('assess_students');

$body = json_decode(file_get_contents('php://input'), true) ?? [];

$studentId  = (int)($body['student_id'] ?? 0);
$rotationId = (int)($body['rotation_id'] ?? 0);
$unitId     = (int)($body['unit_id'] ?? 0);
$comments   = trim((string)($body['comments'] ?? ''));
$scoresIn   = is_array($body['scores'] ?? null) ? $body['scores'] : [];

if (!$studentId || !$rotationId || !$unitId) {
    Api::error(422, 'ValidationError', 'student_id, rotation_id, and unit_id are required');
}

$maxScores = [
    'a1_history_physical' => 5, 'a2_care_plan' => 5, 'a3_clinical_decisions' => 5,
    'a4_documentation' => 5, 'a5_counseling' => 5,
    'b1_appearance' => 5, 'b2_nurse_patient_relation' => 5, 'b3_team_relationship' => 5,
    'b4_responsibility' => 5, 'b5_communication' => 5, 'b6_standards_protocols' => 5,
    'c1_procedures' => 5, 'c2_equipment_use' => 5, 'c3_equipment_maintenance' => 5, 'c4_hospital_economy' => 5,
    'd1_punctuality' => 5, 'd2_clinical_meeting' => 5, 'd3_conference' => 5, 'd4_ward_rounds' => 5,
    'e1_teach_supervise' => 5, 'e2_innovation' => 5,
];

$scores = [];
$totalScore = 0;
$maxPossible = 0;
foreach ($maxScores as $field => $max) {
    $score = min($max, max(0, (int)($scoresIn[$field] ?? 0)));
    $scores[$field] = $score;
    if ($score > 0) {
        $totalScore += $score;
        $maxPossible += $max;
    }
}
$pct = $maxPossible > 0 ? round(($totalScore / $maxPossible) * 100, 2) : 0;
$grade = gradeFor($pct);

// ── Student + unit info, and the same eligibility re-check the pending
// list applies (belt-and-braces against a stale client list). ───────────
$infoStmt = $conn->prepare("
    SELECT cs.id, cs.school_name, srd.unit_name
    FROM clinical_students cs
    JOIN student_rotation_details srd ON srd.clinical_student_id = cs.id
    JOIN clinical_rotations cr ON cr.id = srd.clinical_rotation_id
    WHERE cs.id = ? AND srd.unit_id = ? AND cr.id = ?
    LIMIT 1
");
$infoStmt->bind_param('iii', $studentId, $unitId, $rotationId);
$infoStmt->execute();
$student = $infoStmt->get_result()->fetch_assoc();
$infoStmt->close();
if (!$student) {
    Api::error(404, 'NotFound', 'No matching student/rotation/unit record found.');
}

$existsStmt = $conn->prepare('SELECT id FROM clinical_assessments WHERE clinical_student_id = ? AND unit_id = ? AND clinical_rotation_id = ?');
$existsStmt->bind_param('iii', $studentId, $unitId, $rotationId);
$existsStmt->execute();
$existing = $existsStmt->get_result()->fetch_assoc();
$existsStmt->close();
if ($existing) {
    Api::error(409, 'AlreadyAssessed', 'This student has already been assessed for this unit.');
}

$assessorId = $account->getId();
$assessorName = $account->getFirstname() . ' ' . $account->getSurname();
$assessorRank = $account->getDesignation() ?? '';

$cols = [
    'clinical_student_id', 'clinical_rotation_id', 'unit_id', 'unit_name', 'school',
    'assessment_date', 'total_score', 'max_possible_score', 'percentage_score', 'grade',
    'comments', 'ward_supervisor_name', 'ward_supervisor_rank', 'submitted_by', 'submitted_by_role', 'eval_status',
];
$vals = [
    $studentId, $rotationId, $unitId, $student['unit_name'], $student['school_name'],
    date('Y-m-d'), $totalScore, $maxPossible, $pct, $grade,
    $comments, $assessorName, $assessorRank, $assessorId, 'in_charge', 'submitted',
];
$types = 'iiisssiidssssiss'; // matches the 16 columns above one-for-one (checked against $cols/$vals order)
foreach ($scores as $field => $value) {
    $cols[] = $field;
    $vals[] = $value;
    $types .= 'i';
}

// Sanity check before binding — the single most reliable guard against
// ever repeating the exact class of bug found and fixed in both
// nurse_assessment_form.php and clinical_assessment_form.php this
// session: a type-string/value-count mismatch. Fails loudly and
// immediately instead of silently, if it's ever wrong.
if (strlen($types) !== count($vals)) {
    error_log('student_submit.php: type string length (' . strlen($types) . ') != value count (' . count($vals) . ')');
    Api::error(500, 'ServerError', 'Internal error preparing the assessment record.');
}

$ph = implode(',', array_fill(0, count($vals), '?'));
$sql = 'INSERT INTO clinical_assessments (' . implode(',', $cols) . ") VALUES ($ph)";
$stmt = $conn->prepare($sql);
$stmt->bind_param($types, ...$vals);

if (!$stmt->execute()) {
    Api::error(500, 'ServerError', 'Could not save the assessment. Please try again.');
}
$stmt->close();

Api::success([
    'total_score'  => $totalScore,
    'max_possible' => $maxPossible,
    'percentage'   => $pct,
    'grade'        => $grade,
]);

function gradeFor(float $pct): string
{
    if ($pct >= 80) return 'Excellent';
    if ($pct >= 65) return 'Very Good';
    if ($pct >= 50) return 'Good';
    if ($pct >= 35) return 'Fair';
    return 'Poor';
}
