<?php
// student_action_tabs.php
// ... your session_start/auth/db bootstrap here ...
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// ==== SESSION / ROLE ====
$actor_role = $_SESSION['role'] ?? ($_SESSION['user']['role'] ?? 'guest');
$is_admin   = in_array($actor_role, ['super_admin','branch_admin','admin'], true);

// ==== DB ====
require_once __DIR__ . '/../includes/db.php';
$mysqli = $conn ?? new mysqli("localhost", "root", "", "edencamp_edencampus");
if ($mysqli->connect_error) {
  http_response_code(500);
  exit("Database Connection Failed: " . $mysqli->connect_error);
}

$mysqli->set_charset("utf8mb4");

function stmt_fetch_all_assoc(mysqli_stmt $st): array {
  // Best path if mysqlnd is enabled
  if (method_exists($st, 'get_result')) {
    $res = $st->get_result();
    if ($res) return $res->fetch_all(MYSQLI_ASSOC);
  }

  // Fallback path (bind_result)
  $st->store_result();
  $meta = $st->result_metadata();
  if (!$meta) { $st->free_result(); return []; }

  $fields = $meta->fetch_fields();
  $row = [];
  $bind = [];
  foreach ($fields as $f) {
    $row[$f->name] = null;
    $bind[] = &$row[$f->name];
  }
  $st->bind_result(...$bind);

  $out = [];
  while ($st->fetch()) {
    // IMPORTANT: make a real copy (no references)
    $copy = [];
    foreach ($row as $k => $v) $copy[$k] = $v;
    $out[] = $copy;
  }

  $st->free_result();
  return $out;
}

function stmt_fetch_one_assoc(mysqli_stmt $st): array { $r=stmt_fetch_all_assoc($st); return $r[0]??[]; }
function tableExists(mysqli $db, string $t): bool {
  $st=$db->prepare("SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? LIMIT 1");
  $st->bind_param("s",$t); $st->execute(); $row=stmt_fetch_one_assoc($st); $st->close(); return !empty($row);
}
function colExists(mysqli $db, string $t, string $c): bool {
  $st=$db->prepare("SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=? LIMIT 1");
  $st->bind_param("ss",$t,$c); $st->execute(); $row=stmt_fetch_one_assoc($st); $st->close(); return !empty($row);
}
function ec_get_latest_final_results_per_module(mysqli $db, int $studentId): array {

    $sql = "
    SELECT
      m.id    AS module_id,
      m.title AS module_title,

      r.id        AS result_id,
      r.date_taken,
      r.grade,
      r.status,
      r.score,
      r.total

    FROM studentss s
    JOIN course_modules m
      ON m.course_id = s.course_id

    LEFT JOIN (
      SELECT
        u.module_id,
        MAX(r2.id) AS max_rid
      FROM results r2
      JOIN exams e2  ON e2.id = r2.exam_id
      JOIN units u   ON u.id  = e2.unit_id
      WHERE r2.student_id = ?
        AND (
          LOWER(e2.exam_type) = 'final'
          OR LOWER(e2.title) LIKE '%final%'
          OR LOWER(e2.unit_exam) LIKE '%final%'
        )
      GROUP BY u.module_id
    ) x
      ON x.module_id = m.id

    LEFT JOIN results r
      ON r.id = x.max_rid

    WHERE s.id = ?
    ORDER BY m.sort_order, m.id
    ";

    $stmt = $db->prepare($sql);
    if (!$stmt) {
        throw new Exception('Prepare failed: ' . $db->error);
    }

    $stmt->bind_param("ii", $studentId, $studentId);
    $stmt->execute();
    $res = $stmt->get_result();

    $rows = [];
    while ($row = $res->fetch_assoc()) {
        $rows[] = $row;
    }
    $stmt->close();
    return $rows;
}
// ===== Latest FINAL result per UNIT for a given COURSE (bundle-safe) =====
if (!function_exists('ec_get_latest_final_results_per_unit_for_course')) {

function ec_get_latest_final_results_per_unit_for_course(mysqli $db, int $studentId, int $courseId, array $lessonTitles = []): array
{
  if ($studentId <= 0 || $courseId <= 0) return [];
  if (!tableExists($db,'results') || !tableExists($db,'exams')) return [];

  // ---------- expand bundle parent -> include child course ids ----------
  $courseIds = [$courseId];
  if (tableExists($db,'course_children')) {
    if ($st = $db->prepare("SELECT child_id FROM course_children WHERE parent_id=?")) {
      $st->bind_param('i', $courseId);
      $st->execute();
      if ($rs = $st->get_result()) {
        while ($r = $rs->fetch_assoc()) $courseIds[] = (int)$r['child_id'];
      }
      $st->close();
    }
  }
  $courseIds = array_values(array_unique(array_filter(array_map('intval', $courseIds))));
  if (!$courseIds) $courseIds = [$courseId];

  // ---------- prepare lesson title index (for label->unit matching) ----------
  $titleIndexByNorm = [];
  if (!empty($lessonTitles) && function_exists('ec_norm_key')) {
    foreach ($lessonTitles as $i => $t) {
      $k = ec_norm_key((string)$t);
      if ($k !== '') $titleIndexByNorm[$k] = $i + 1; // 1-based
    }
  }

  // ---------- student reference key (optional) ----------
  $ref_key = '';
  if (tableExists($db, 'studentss')) {
    $cols = [];
    foreach (['reference_no','ref_no','reference_number'] as $c) {
      if (colExists($db, 'studentss', $c)) $cols[] = "`$c`";
    }
    if ($cols) {
      $sqlRef = "SELECT " . implode(',', $cols) . " FROM studentss WHERE id=? LIMIT 1";
      if ($st = $db->prepare($sqlRef)) {
        $st->bind_param('i', $studentId);
        $st->execute();
        $row = stmt_fetch_one_assoc($st);
        $st->close();
        $ref_key = trim((string)($row['reference_no'] ?? $row['ref_no'] ?? $row['reference_number'] ?? ''));
      }
    }
  }

  // ---------- student match (student_id OR ref column) ----------
  $refCol = null;
  foreach (['reference_no','ref_no','student_ref_no'] as $c) {
    if (colExists($db, 'results', $c)) { $refCol = $c; break; }
  }

  $conds = [];
  $types = '';
  $params = [];

  if (colExists($db, 'results', 'student_id')) {
    $conds[] = "r.student_id = ?";
    $types .= 'i';
    $params[] = $studentId;
  }
  if ($refCol && $ref_key !== '') {
    $conds[] = "r.`$refCol` = ?";
    $types .= 's';
    $params[] = $ref_key;
  }
  $whereStudent = $conds ? '(' . implode(' OR ', $conds) . ')' : '1=0';

  // ---------- robust FINAL filter ----------
  $finalParts = [];
  if (colExists($db,'results','module_name')) $finalParts[] = "LOWER(COALESCE(r.module_name,'')) LIKE '%final%'";
  if (colExists($db,'exams','unit_exam'))    $finalParts[] = "LOWER(COALESCE(e.unit_exam,'')) LIKE '%final%'";
  if (colExists($db,'exams','title'))        $finalParts[] = "LOWER(COALESCE(e.title,'')) LIKE '%final%'";
  if (colExists($db,'exams','type'))         $finalParts[] = "LOWER(COALESCE(e.type,'')) LIKE '%final%'";
  if (colExists($db,'exams','exam_type'))    $finalParts[] = "LOWER(COALESCE(e.exam_type,'')) LIKE '%final%'";
  $finalSQL = $finalParts ? (" AND (" . implode(" OR ", $finalParts) . ")") : "";

  // ---------- label expression ----------
  $labelExpr = [];
  if (colExists($db,'exams','unit_exam')) $labelExpr[] = "NULLIF(TRIM(e.unit_exam),'')";
  if (colExists($db,'exams','title'))     $labelExpr[] = "NULLIF(TRIM(e.title),'')";
  if (colExists($db,'results','module_name')) $labelExpr[] = "NULLIF(TRIM(r.module_name),'')";
  $labelSQL = $labelExpr ? "COALESCE(".implode(',',$labelExpr).",'Exam')" : "'Exam'";

  // ---------- dynamic columns for results ----------
  $dateCol = null;
  foreach (['date_taken','when_taken','taken_at','created_at','updated_at'] as $c) {
    if (colExists($db,'results',$c)) { $dateCol = $c; break; }
  }
  $scoreCol = null;
  foreach (['score','marks','mark','obtained_marks'] as $c) {
    if (colExists($db,'results',$c)) { $scoreCol = $c; break; }
  }
  $totalCol = null;
  foreach (['total','total_marks','out_of'] as $c) {
    if (colExists($db,'results',$c)) { $totalCol = $c; break; }
  }
  $gradeCol  = colExists($db,'results','grade')  ? 'grade'  : null;
  $statusCol = colExists($db,'results','status') ? 'status' : null;

  $selDate  = $dateCol  ? "r.`$dateCol`  AS date_taken" : "NULL AS date_taken";
  $selScore = $scoreCol ? "r.`$scoreCol` AS score"      : "NULL AS score";
  $selTotal = $totalCol ? "r.`$totalCol` AS total"      : "NULL AS total";
  $selGrade = $gradeCol ? "r.`$gradeCol` AS grade"      : "NULL AS grade";
  $selStat  = $statusCol? "r.`$statusCol` AS status"    : "NULL AS status";

  // ---------- course filter in SQL (supports IN for bundles) ----------
  $hasECourse = colExists($db,'exams','course_id');
  $hasRCourse = colExists($db,'results','course_id');

  $courseFilter = "";
  if ($hasECourse) {
    if (count($courseIds) === 1) {
      $courseFilter = " AND e.course_id = ?";
      $types .= 'i'; $params[] = $courseIds[0];
    } else {
      $ph = implode(',', array_fill(0, count($courseIds), '?'));
      $courseFilter = " AND e.course_id IN ($ph)";
      $types .= str_repeat('i', count($courseIds));
      foreach ($courseIds as $cid) $params[] = $cid;
    }
  } elseif ($hasRCourse) {
    if (count($courseIds) === 1) {
      $courseFilter = " AND r.course_id = ?";
      $types .= 'i'; $params[] = $courseIds[0];
    } else {
      $ph = implode(',', array_fill(0, count($courseIds), '?'));
      $courseFilter = " AND r.course_id IN ($ph)";
      $types .= str_repeat('i', count($courseIds));
      foreach ($courseIds as $cid) $params[] = $cid;
    }
  }

  $unitExpr = colExists($db,'exams','unit_id') ? "COALESCE(e.unit_id,0) AS unit_id" : "0 AS unit_id";

    $sql = "
    SELECT
      e.id AS exam_id,
      $unitExpr,
      $labelSQL AS label,
      r.id AS result_id,
      $selDate,
      $selGrade,
      $selStat,
      $selScore,
      $selTotal
    FROM results r
    JOIN exams e ON e.id = r.exam_id
    WHERE
      $whereStudent
      $courseFilter
      $finalSQL
    ORDER BY
      COALESCE(date_taken, '1970-01-01') DESC,
      r.id DESC
  ";


  $rows = [];
  if ($st = $db->prepare($sql)) {
    if ($types !== '') $st->bind_param($types, ...$params);
    $st->execute();
    $rows = stmt_fetch_all_assoc($st);
    $st->close();
  }

  // ---------- keep latest per unit (unit_id > unit_no > title-match > exam_id) ----------
  $latest = [];

  foreach ($rows as $r) {
    $examId = (int)($r['exam_id'] ?? 0);
    $unitId = (int)($r['unit_id'] ?? 0);
    $label  = (string)($r['label'] ?? 'Exam');

    $unitNo = 0;

    // 1) detect "Unit 01" patterns
    if (preg_match('/\bunit[\s\-_:\.]*0*([0-9]{1,2})\b/i', $label, $m)) {
      $unitNo = (int)$m[1];
    }

    // 2) if no unitNo, try matching label to lesson title
    if ($unitNo <= 0 && $titleIndexByNorm && function_exists('ec_norm_key')) {
      $lk = ec_norm_key($label);
      if ($lk !== '' && isset($titleIndexByNorm[$lk])) {
        $unitNo = (int)$titleIndexByNorm[$lk];
      }
    }

    if ($unitId > 0) $key = 'uid:' . $unitId;
    elseif ($unitNo > 0) $key = 'uno:' . $unitNo;
    else $key = 'exam:' . $examId;

    if (!isset($latest[$key])) {
      $latest[$key] = [
        'unit_id'    => $unitId ?: null,
        '_unit_no'   => $unitNo ?: null,
        'unit_name'  => $label,
        'exam_label' => $label,
        'exam_id'    => $examId ?: null,
        'result_id'  => (int)($r['result_id'] ?? 0),
        'date_taken' => $r['date_taken'] ?? null,
        'grade'      => $r['grade'] ?? null,
        'status'     => $r['status'] ?? null,
        'score'      => $r['score'] ?? null,
        'total'      => $r['total'] ?? null,
      ];
    }
  }

  // ---------- output in lesson order if titles provided ----------
  $out = [];

  if (!empty($lessonTitles)) {
    $count = count($lessonTitles);

    for ($i=1; $i<=$count; $i++) {
      $title = trim((string)$lessonTitles[$i-1]);
      if ($title === '') $title = 'Unit '.$i;

      $found = $latest['uno:'.$i] ?? null;

      if ($found) {
        $found['unit_name'] = $title;
        unset($found['_unit_no']);
        $out[] = $found;
      } else {
        $out[] = [
          'unit_id'    => null,
          'unit_name'  => $title,
          'exam_label' => null,
          'exam_id'    => null,
          'result_id'  => null,
          'date_taken' => null,
          'grade'      => null,
          'status'     => null,
          'score'      => null,
          'total'      => null,
        ];
      }
    }

    // append anything not mapped to uno: (keep uid: + exam:)
    foreach ($latest as $k => $v) {
      if (strpos($k,'uno:') === 0) continue;
      $v['unit_name'] = $v['unit_name'] ?: ($v['exam_label'] ?: 'Final Exam');
      unset($v['_unit_no']);
      $out[] = $v;
    }

    return $out;
  }

  foreach ($latest as $v) {
    unset($v['_unit_no']);
    $out[] = $v;
  }

  return $out;
}

}



/**
 * Return ALL batch rows for a given student (bundle-aware),
 * no matter which mapping table is used.
 *
 * @param mysqli $db
 * @param int    $studentId   studentss.id (numeric PK)
 * @return array[]            each: ['id','batch_code','status']
 */
function ec_get_student_batches(mysqli $db, int $studentId, int $courseId = 0): array
{
    $rows = [];

    $sql = "
        SELECT DISTINCT
            e.id AS enrollment_id,
            e.batch_id,
            b.batch_code,
            b.status,
            b.course_id
        FROM enrollments AS e
        INNER JOIN batches AS b
            ON b.id = e.batch_id
        WHERE e.student_id = ?
    ";

    if ($courseId > 0) {
        $sql .= " AND b.course_id = ? ";
    }

    $sql .= " ORDER BY b.id ASC ";

    if ($st = $db->prepare($sql)) {
        if ($courseId > 0) {
            $st->bind_param('ii', $studentId, $courseId);
        } else {
            $st->bind_param('i', $studentId);
        }

        if ($st->execute() && ($res = $st->get_result())) {
            while ($r = $res->fetch_assoc()) {
                $rows[] = $r;
            }
        }
        $st->close();
    }

    return $rows;
}
/**
 * Collapse exam rows so that, for each course, we keep only
 * the latest attempt per module_name.
 *
 * @param array $evalByCourse  [course_id => [ [row], [row], ... ]]
 * @return array               same shape but one row per module_name
 */
 
 function ec_get_student_batch_id_for_course(mysqli $db, int $studentId, int $courseId): int
{
    if ($studentId <= 0 || $courseId <= 0) return 0;

    $sql = "
        SELECT b.id
        FROM enrollments e
        JOIN batches b ON b.id = e.batch_id
        WHERE e.student_id = ?
          AND b.course_id = ?
        ORDER BY b.id DESC
        LIMIT 1
    ";

    $st = $db->prepare($sql);
    $st->bind_param('ii', $studentId, $courseId);
    $st->execute();
    $row = stmt_fetch_one_assoc($st);
    $st->close();

    return (int)($row['id'] ?? 0);
}
 
function ec_collapse_latest_exam_per_module(array $evalByCourse): array
{
    $out = [];

    foreach ($evalByCourse as $cid => $rows) {
        $cid = (int)$cid;
        if (!$rows) {
            $out[$cid] = [];
            continue;
        }

        $byModule = [];

        foreach ($rows as $row) {
            $moduleName = ec_norm_key((string)($row['module_name'] ?? ''));
            if ($moduleName === '') {
                // If no module name, just push as a separate row
                $byModule[] = $row;
                continue;
            }

            $whenNew = trim((string)($row['when_taken'] ?? ''));
            $current = $byModule[$moduleName] ?? null;
            $whenCur = $current ? trim((string)($current['when_taken'] ?? '')) : '';

            // If we don't have a row yet, or new one is clearly newer, replace
            if (!$current) {
                $byModule[$moduleName] = $row;
                continue;
            }

            if ($whenNew === '' && $whenCur !== '') {
                // keep the one that actually has a date
                continue;
            }

            if ($whenNew !== '' && $whenCur === '') {
                $byModule[$moduleName] = $row;
                continue;
            }

            if ($whenNew !== '' && $whenCur !== '') {
                if (strtotime($whenNew) > strtotime($whenCur)) {
                    $byModule[$moduleName] = $row;
                }
            }
        }

        // Re-index for easier looping later
        $out[$cid] = array_values($byModule);
    }

    return $out;
}

/**
 * Try to map an exam "unit" label (e.g. "Unit 01 Final Exam")
 * to a nicer child-course/module title using $child_lessons[$cid].
 *
 * @param string $moduleLabel   e.g. "Unit 01 - Final Exam"
 * @param array  $childTitles   ordered list of lesson/unit titles
 * @return string               mapped title or original label
 */
function ec_map_unit_label_to_child_title(string $moduleLabel, array $childTitles): string
{
    if (!$childTitles) return $moduleLabel;

    $norm = trim($moduleLabel);
    if ($norm === '') return $moduleLabel;

    // ✅ allow Unit-02 / Unit_02 / Unit 02 / Unit:02 etc + leading zeros
    if (preg_match('/\bunit[\s\-_:\.]*0*([0-9]{1,2})\b/i', $norm, $m)) {
        $idx = max(1, (int)$m[1]) - 1;
        if (!empty($childTitles[$idx])) return $childTitles[$idx];
    }

    return $moduleLabel;
}




// ===== your existing code continues here =====
// e.g. loading $student by id, etc.

$is_embed = (isset($_GET['modal']) && $_GET['modal'] === '1');

// ==== INPUT ====
$student_id = (int)($_POST['id'] ?? $_GET['id'] ?? $_POST['student_id'] ?? $_GET['student_id'] ?? $_GET['sid'] ?? 0);
if ($student_id <= 0) { http_response_code(400); exit('Invalid student id.'); }

$course_id = (int)($_GET['course_id'] ?? $_POST['course_id'] ?? 0);

/* safe default first */
$filter_course_ids = $course_id > 0 ? [$course_id] : [];
$scope_child_ids   = [];

if ($filter_course_ids) {
  $tmp = array_map('intval', $filter_course_ids);

  if (tableExists($mysqli,'course_children')) {
    $in = implode(',', $tmp);
    $map = [];
    if ($in) {
      $rs = $mysqli->query("SELECT parent_id, child_id FROM course_children WHERE parent_id IN ($in)");
      if ($rs) { while ($r = $rs->fetch_assoc()) $map[(int)$r['parent_id']][] = (int)$r['child_id']; $rs->free(); }
    }
    foreach ($tmp as $cid) {
      if (!empty($map[$cid])) $scope_child_ids = array_merge($scope_child_ids, $map[$cid]);
      else $scope_child_ids[] = $cid; // single course
    }
  } else {
    $scope_child_ids = $tmp;
  }
}
$scope_child_ids = array_values(array_unique(array_filter($scope_child_ids)));

// ==== HELPERS ====
if (!function_exists('h')) {
  function h($s): string {
    if ($s === null) return '';
    // avoid warnings if something non-string is passed
    if (is_array($s) || is_object($s)) {
      $s = json_encode($s, JSON_UNESCAPED_UNICODE);
    }
    return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
  }
}

function esc($s){ return h($s); }
function nf($n,$d=2){ return number_format((float)$n,$d); }
function numf($v): float {
  $s = preg_replace('/[^0-9.\-]/', '', (string)$v);
  if ($s === '' || $s === '-' || $s === '.' || $s === '-.') return 0.0;
  $n = (float)$s;
  return is_finite($n) ? $n : 0.0;
}
/**
 * Decide Result (Pass/Fail) from grade or marks.
 */
function ec_result_from_grade(string $grade, float $score = 0, float $total = 0): string {
    $g = strtolower(trim($grade));

    if ($g === '') return '-';
    if (in_array($g, ['f','fail','failed'], true)) return 'Fail';
    if (in_array($g, ['pass','passed','p'], true)) return 'Pass';

    // If it's like A/B/C/D etc
    if (preg_match('/^[a-d][+-]?$/i', $grade)) return 'Pass';

    // Fallback by marks if available
    if ($total > 0) {
        $pct = ($score / $total) * 100.0;
        return ($pct >= 50.0) ? 'Pass' : 'Fail';
    }

    return '-';
}

// ==== WORKING Evaluation Attempts helpers (ported from staction_tabs.php) ====
if (!function_exists('get_course_ids_for_modules')) {
  function get_course_ids_for_modules(mysqli $db, int $selected_course_id): array {
    $ids = [];

    // If selected course has modules => include it
    if ($st = $db->prepare("SELECT 1 FROM course_modules WHERE course_id=? LIMIT 1")) {
      $st->bind_param("i", $selected_course_id);
      $st->execute();
      $st->store_result();
      if ($st->num_rows > 0) $ids[] = $selected_course_id;
      $st->close();
    }

    // If it's a bundle parent => include children that have modules
    if ($st = $db->prepare("SELECT child_id FROM course_children WHERE parent_id=? ORDER BY sort_order ASC, child_id ASC")) {
      $st->bind_param("i", $selected_course_id);
      $st->execute();
      if (method_exists($st, 'get_result')) {
        if ($rs = $st->get_result()) {
          while ($r = $rs->fetch_assoc()) {
            $cid = (int)($r['child_id'] ?? 0);
            if ($cid <= 0) continue;

            if ($st2 = $db->prepare("SELECT 1 FROM course_modules WHERE course_id=? LIMIT 1")) {
              $st2->bind_param("i", $cid);
              $st2->execute();
              $st2->store_result();
              if ($st2->num_rows > 0) $ids[] = $cid;
              $st2->close();
            }
          }
        }
      } else {
        foreach (stmt_fetch_all_assoc($st) as $r) {
          $cid = (int)($r['child_id'] ?? 0);
          if ($cid <= 0) continue;

          if ($st2 = $db->prepare("SELECT 1 FROM course_modules WHERE course_id=? LIMIT 1")) {
            $st2->bind_param("i", $cid);
            $st2->execute();
            $st2->store_result();
            if ($st2->num_rows > 0) $ids[] = $cid;
            $st2->close();
          }
        }
      }
      $st->close();
    }

    return $ids ?: [$selected_course_id];
  }
}

if (!function_exists('get_modules_with_final_last_result')) {
  function get_modules_with_final_last_result(
    mysqli $db,
    int $student_id,
    array $course_ids,
    string $reg_no,
    string $ec1,
    string $ec2
  ): array {
    if (!$course_ids) return [];

    // safe int list
    $course_ids = array_values(array_unique(array_map('intval', $course_ids)));
    $in = implode(',', $course_ids);

    $sql = "
      SELECT
        cm.course_id,
        c.course_name,

        cm.id    AS module_id,
        cm.title AS module_name,

        CASE
          WHEN LOWER(cm.title) LIKE '%finalproject%' THEN 'Software Project'
          ELSE 'Online Exam'
        END AS evaluation_method,
        'Final' AS evaluation_type,

        r.date_taken AS date_evaluated,
        r.grade,

        COALESCE(
          NULLIF(TRIM(r.status), ''),
          CASE
            WHEN r.id IS NULL THEN NULL
            WHEN COALESCE(r.total,0) <= 0 THEN NULL
            WHEN (r.score * 100.0 / r.total) >= COALESCE(e.pass_mark, 40) THEN 'Pass'
            ELSE 'Fail'
          END
        ) AS result

      FROM course_modules cm
      LEFT JOIN courses c ON c.id = cm.course_id

      /* Pick the FINAL unit for each module */
      LEFT JOIN (
        SELECT
          course_id,
          module_id,
          COALESCE(
            MAX(CASE WHEN name LIKE '%Final Exam%' THEN id END),
            MAX(CASE WHEN name LIKE '%Final%'     THEN id END)
          ) AS final_unit_id
        FROM units
        GROUP BY course_id, module_id
      ) fu
        ON fu.course_id = cm.course_id
       AND fu.module_id = cm.id

      /* Pick the FINAL exam for that FINAL unit */
      LEFT JOIN (
        SELECT
          course_id,
          unit_id,
          COALESCE(
            MAX(CASE WHEN unit_exam LIKE '%Final Exam%' THEN id END),
            MAX(CASE WHEN title    LIKE '%Final Exam%' THEN id END),
            MAX(CASE WHEN unit_exam LIKE '%Final%'     THEN id END),
            MAX(CASE WHEN title    LIKE '%Final%'     THEN id END),
            MAX(id)
          ) AS final_exam_id
        FROM exams
        GROUP BY course_id, unit_id
      ) fe
        ON fe.course_id = cm.course_id
       AND fe.unit_id   = fu.final_unit_id

      LEFT JOIN exams e ON e.id = fe.final_exam_id

      /* Last attempt per exam for this person (match by student_id OR reference_no) */
      LEFT JOIN (
        SELECT
          exam_id,
          MAX(id) AS last_result_id
        FROM results
        WHERE
          student_id = ?
          OR reference_no IN (?,?,?)
        GROUP BY exam_id
      ) lr
        ON lr.exam_id = e.id

      LEFT JOIN results r
        ON r.id = lr.last_result_id

      WHERE cm.course_id IN ($in)
      ORDER BY cm.course_id ASC, COALESCE(cm.sort_order, 9999) ASC, cm.id ASC
    ";

    $st = $db->prepare($sql);
    if (!$st) return [];

    // bind: student_id + reg_no + ec1 + ec2
    $st->bind_param("isss", $student_id, $reg_no, $ec1, $ec2);
    $st->execute();
    $rs = $st->get_result();
    $rows = $rs ? $rs->fetch_all(MYSQLI_ASSOC) : [];
    $st->close();

    return $rows;
  }
}


// Normalize a string key so "Unit-01", "Unit 01", "UNIT_01" match the same.
// Used to match lesson titles with exam module names reliably.
if (!function_exists('ec_norm_key')) {
  function ec_norm_key($s): string {
    if ($s === null) return '';
    if (is_array($s) || is_object($s)) $s = json_encode($s, JSON_UNESCAPED_UNICODE);

    $s = (string)$s;
    $s = html_entity_decode(strip_tags($s), ENT_QUOTES, 'UTF-8');
    $s = strtolower($s);

    // remove zero-width chars
    $s = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', '', $s);

    // convert punctuation/underscores/dashes to spaces, keep letters+numbers
    $s = preg_replace('/[^\p{L}\p{N}]+/u', ' ', $s);

    // collapse spaces
    $s = trim(preg_replace('/\s+/', ' ', $s));

    // normalize leading zeros in numbers: 01 -> 1
    $s = preg_replace_callback('/\b0+(\d+)\b/', function($m){
      return (string)((int)$m[1]);
    }, $s);

    return $s;
  }
}

/**
 * Build "Evaluation Attempts" rows in the same format as your screenshot:
 * Module | Evaluation Method | Type | Date Evaluated | Grade | Result
 *
 * It lists ALL modules (lesson plan titles) and fills data from latest attempt.
 */
function ec_build_evaluation_plan_rows(array $lessonTitles, array $examRows): array
{
    $latest = []; // normTitle => row

    foreach ($examRows as $r) {
        $moduleRaw = (string)($r['module_name'] ?? '');
        $module = ec_norm_key($moduleRaw);
        if ($module === '') continue;

        $whenNew = trim((string)($r['when_taken'] ?? ''));
        $cur     = $latest[$module] ?? null;
        $whenCur = $cur ? trim((string)($cur['when_taken'] ?? '')) : '';

        if (!$cur) { $latest[$module] = $r; continue; }

        if ($whenNew !== '' && $whenCur === '') { $latest[$module] = $r; continue; }
        if ($whenNew === '' && $whenCur !== '') { continue; }
        if ($whenNew !== '' && $whenCur !== '' && strtotime($whenNew) > strtotime($whenCur)) {
            $latest[$module] = $r;
        }
    }

    $out = [];
    foreach ($lessonTitles as $title) {
        $titleRaw = trim((string)$title);
        if ($titleRaw === '') continue;

        $key = ec_norm_key($titleRaw);
        $r = $latest[$key] ?? null;

        $score = $r ? (float)($r['score'] ?? 0) : 0.0;
        $total = $r ? (float)($r['total'] ?? 0) : 0.0;
        $grade = $r ? trim((string)($r['grade'] ?? '')) : '';
        $date  = $r ? trim((string)($r['when_taken'] ?? '')) : '';

        $out[] = [
            'module'  => $titleRaw,
            'method'  => 'Online Exam',
            'type'    => 'Final',
            'date'    => $date !== '' ? $date : '-',
            'grade'   => $grade !== '' ? $grade : '-',
            'result'  => $r ? ec_result_from_grade($grade, $score, $total) : '-',
        ];
    }

    return $out;
}

/**
 * ===== Marks-Validation style FINAL exam + LAST attempt result helpers =====
 * Works even if `results.student_id` points to `students.id` (exam system)
 * OR if results uses `reference_no` (NEC/EC) matching.
 */

function ec_pick_col(mysqli $db, string $table, array $cands): ?string {
  foreach ($cands as $c) {
    if (colExists($db, $table, $c)) return $c;
  }
  return null;
}

/** Prefer NEC (center_reg_no) then EC (reference_no/reference_no2) */
function ec_get_student_ref_keys(array $student, array $refs_by_course_for_this_child = []): array {
  $keys = [];

  $nec = trim((string)($student['center_reg_no'] ?? $student['center_registration_no'] ?? $student['center_no'] ?? $student['center_reg'] ?? ''));
  $ec1 = trim((string)($student['reference_no'] ?? $student['ref_no'] ?? $student['reference_number'] ?? ''));
  $ec2 = trim((string)($student['reference_no2'] ?? $student['ref_no2'] ?? ''));

  if ($nec !== '') $keys[] = $nec;
  if ($ec1 !== '') $keys[] = $ec1;
  if ($ec2 !== '') $keys[] = $ec2;

  // Also add per-course ECs from student_numbers (bundle children)
  $c1 = trim((string)($refs_by_course_for_this_child['ec1'] ?? ''));
  $c2 = trim((string)($refs_by_course_for_this_child['ec2'] ?? ''));
  if ($c1 !== '') $keys[] = $c1;
  if ($c2 !== '') $keys[] = $c2;

  $keys = array_values(array_unique(array_filter($keys, fn($v)=>$v!=='')));
  return $keys;
}

/**
 * Map studentss -> exam-system students.id (optional).
 * If your results.student_id stores `students.id`, this is REQUIRED.
 */
function ec_get_exam_students_id(mysqli $db, array $student, array $refs_by_course_for_this_child = []): ?int {
  if (!tableExists($db, 'students')) return null;
  if (!colExists($db, 'students', 'course_reg_no')) return null;

  $refKeys = ec_get_student_ref_keys($student, $refs_by_course_for_this_child);
  if (!$refKeys) return null;

  $ph = implode(',', array_fill(0, count($refKeys), '?'));
  $types = str_repeat('s', count($refKeys));

  $sql = "SELECT id
          FROM students
          WHERE course_reg_no IN ($ph)
          ORDER BY id DESC
          LIMIT 1";
  $st = $db->prepare($sql);
  $st->bind_param($types, ...$refKeys);
  $st->execute();
  $row = stmt_fetch_one_assoc($st);
  $st->close();

  $id = (int)($row['id'] ?? 0);
  return $id > 0 ? $id : null;
}

/**
 * Get ordered "modules" exactly like Marks Validation:
 * - from course_modules (preferred)
 * - unit_no = sort_order if present else sequential index
 * Returns: [ ['module_id'=>int,'unit_no'=>int,'title'=>string], ... ]
 */
function ec_get_modules_like_marks_validation(mysqli $db, int $course_id): array {
  $out = [];

  if (tableExists($db,'course_modules')) {
    $titleCol = ec_pick_col($db,'course_modules',['title','module_name','name']);
    $orderCol = ec_pick_col($db,'course_modules',['sort_order','order_no','module_no','position']);
    if ($titleCol) {
      $sql = "SELECT id, `$titleCol` AS title".($orderCol? ", `$orderCol` AS ord":"")."
              FROM course_modules
              WHERE course_id=?
              ORDER BY ".($orderCol? "`$orderCol`":"id");
      $st = $db->prepare($sql);
      $st->bind_param("i",$course_id);
      $st->execute();
      $res = $st->get_result();
      $i=0;
      while($r=$res->fetch_assoc()){
        $t = trim((string)($r['title'] ?? ''));
        if ($t==='') continue;
        $i++;
        $unitNo = $orderCol ? (int)($r['ord'] ?? $i) : $i;
        if ($unitNo <= 0) $unitNo = $i;
        $out[] = ['module_id'=>(int)$r['id'], 'unit_no'=>$unitNo, 'title'=>$t];
      }
      $st->close();
      if ($out) return $out;
    }
  }

  // fallback: courses.modules CSV/JSON not recommended, but keep safe
  if (tableExists($db,'courses') && colExists($db,'courses','modules')) {
    $st = $db->prepare("SELECT modules FROM courses WHERE id=? LIMIT 1");
    $st->bind_param("i",$course_id);
    $st->execute();
    $row = stmt_fetch_one_assoc($st);
    $st->close();
    $mod = (string)($row['modules'] ?? '');
    if ($mod !== '') {
      $i=0;
      $j = json_decode($mod, true);
      if (is_array($j)) {
        foreach ($j as $item) {
          $t = is_array($item) ? trim((string)($item['title'] ?? $item['name'] ?? '')) : trim((string)$item);
          if ($t==='') continue;
          $i++;
          $out[] = ['module_id'=>0-$i, 'unit_no'=>$i, 'title'=>$t];
        }
        return $out;
      }
      foreach (explode(',', $mod) as $t) {
        $t = trim($t);
        if ($t==='') continue;
        $i++;
        $out[] = ['module_id'=>0-$i, 'unit_no'=>$i, 'title'=>$t];
      }
    }
  }

  return $out;
}

function ec_find_final_exam_id_for_unit(mysqli $db, int $course_id, int $unit_no, int $module_id = 0): ?int {
  if ($course_id <= 0 || $unit_no <= 0) return null;
  if (!tableExists($db,'exams')) return null;

  $haveUnits  = tableExists($db,'units');
  $eHasCourse = colExists($db,'exams','course_id');
  if (!$eHasCourse) return null;

  // ---- pick existing exams columns ----
  $eTitleCol = colExists($db,'exams','title') ? 'title' : null;
  $eUnitCol  = colExists($db,'exams','unit_exam') ? 'unit_exam' : null;
  $eTypeCol  = colExists($db,'exams','exam_type') ? 'exam_type' : (colExists($db,'exams','type') ? 'type' : null);

  // ---- pick existing units columns ----
  $uNameCol   = $haveUnits ? (colExists($db,'units','name') ? 'name' : (colExists($db,'units','title') ? 'title' : null)) : null;
  $uCourseCol = $haveUnits && colExists($db,'units','course_id') ? 'course_id' : null;
  $uHasModule = $haveUnits && colExists($db,'units','module_id');

  // ---- build FINAL condition (only existing columns) ----
  $finalParts = [];
  if ($uNameCol)  $finalParts[] = "u.`$uNameCol` LIKE '%Final%'";
  if ($eTitleCol) $finalParts[] = "e.`$eTitleCol` LIKE '%Final%'";
  if ($eUnitCol)  $finalParts[] = "e.`$eUnitCol` LIKE '%Final%'";
  if ($eTypeCol)  $finalParts[] = "e.`$eTypeCol` LIKE '%Final%'";
  $finalSQL = $finalParts ? (" AND (" . implode(" OR ", $finalParts) . ")") : "";

  // regex safe: Unit 1 must not match Unit 10
  $unitReUnits = '^Unit[[:space:]]*0?' . $unit_no . '([^0-9]|$)';
  $unitReExams = 'Unit[[:space:]]*0?' . $unit_no . '([^0-9]|$)';

  // =========================================================
  // 1) BEST: exams + units by units.module_id (if available)
  // =========================================================
  if ($haveUnits && $uHasModule && $module_id > 0) {

    // only add u.course_id filter if it exists
    $uCourseFilter = $uCourseCol ? " AND u.`$uCourseCol`=?" : "";

    $sql = "
      SELECT e.id
      FROM exams e
      JOIN units u ON u.id = e.unit_id
      WHERE e.course_id=?
        $uCourseFilter
        AND u.module_id=?
        $finalSQL
      ORDER BY e.id DESC
      LIMIT 1
    ";

    $st = $db->prepare($sql);

    if ($uCourseCol) {
      $st->bind_param("iii", $course_id, $course_id, $module_id);
    } else {
      $st->bind_param("ii", $course_id, $module_id);
    }

    $st->execute();
    $r = stmt_fetch_one_assoc($st);
    $st->close();

    $eid = (int)($r['id'] ?? 0);
    if ($eid > 0) return $eid;
  }

  // =========================================================
  // 2) exams + units by unit name regexp (if units has a name/title)
  // =========================================================
  if ($haveUnits && $uNameCol) {

    $uCourseFilter = $uCourseCol ? " AND u.`$uCourseCol`=?" : "";

    $sql = "
      SELECT e.id
      FROM exams e
      JOIN units u ON u.id = e.unit_id
      WHERE e.course_id=?
        $uCourseFilter
        AND u.`$uNameCol` REGEXP ?
        $finalSQL
      ORDER BY e.id DESC
      LIMIT 1
    ";

    $st = $db->prepare($sql);

    if ($uCourseCol) {
      $st->bind_param("iis", $course_id, $course_id, $unitReUnits);
    } else {
      $st->bind_param("is", $course_id, $unitReUnits);
    }

    $st->execute();
    $r = stmt_fetch_one_assoc($st);
    $st->close();

    $eid = (int)($r['id'] ?? 0);
    if ($eid > 0) return $eid;
  }

  // =========================================================
  // 3) exams only fallback (use title/unit_exam/exam_type if exist)
  // =========================================================
  $examUnitMatchParts = [];
  if ($eTitleCol) $examUnitMatchParts[] = "e.`$eTitleCol` REGEXP ?";
  if ($eUnitCol)  $examUnitMatchParts[] = "e.`$eUnitCol` REGEXP ?";

  // If neither title nor unit_exam exists, we cannot do fallback match
  if (!$examUnitMatchParts) return null;

  // final condition for exams-only (only existing columns)
  $finalExamOnlyParts = [];
  if ($eTitleCol) $finalExamOnlyParts[] = "e.`$eTitleCol` LIKE '%Final%'";
  if ($eUnitCol)  $finalExamOnlyParts[] = "e.`$eUnitCol` LIKE '%Final%'";
  if ($eTypeCol)  $finalExamOnlyParts[] = "e.`$eTypeCol` LIKE '%Final%'";
  $finalExamOnlySQL = $finalExamOnlyParts ? (" AND (" . implode(" OR ", $finalExamOnlyParts) . ")") : "";

  $sql = "
    SELECT e.id
    FROM exams e
    WHERE e.course_id=?
      $finalExamOnlySQL
      AND (" . implode(" OR ", $examUnitMatchParts) . ")
    ORDER BY e.id DESC
    LIMIT 1
  ";

  $st = $db->prepare($sql);

  // bind params: course_id + (unitRe for each REGEXP)
  $types = "i";
  $params = [$course_id];

  // same regex used for both title/unit_exam
  foreach ($examUnitMatchParts as $_) {
    $types .= "s";
    $params[] = $unitReExams;
  }

  $st->bind_param($types, ...$params);
  $st->execute();
  $r = stmt_fetch_one_assoc($st);
  $st->close();

  $eid = (int)($r['id'] ?? 0);
  return $eid > 0 ? $eid : null;
}


/**
 * Fetch LAST attempt result row for ONE exam id for THIS student using Marks-Validation matching:
 * - if results.reference_no exists => match by reference keys (NEC/EC/EC2)
 * - else match by results.student_id using (students.id if found) OR fallback studentss.id
 */
function ec_get_last_result_for_exam(mysqli $db, int $exam_id, int $studentss_id, array $refKeys, ?int $exam_students_id): ?array {
  if ($exam_id <= 0) return null;
  if (!tableExists($db,'results')) return null;

  $rCols = [];
  // dynamic cols
  $refCol     = ec_pick_col($db,'results',['reference_no','reference_no2','student_ref_no','student_ref','course_reg_no','reg_no']);
  $studentCol = ec_pick_col($db,'results',['student_id','students_id','studentss_id','std_id','studentId']);
  $dateCol    = ec_pick_col($db,'results',['date_taken','when_taken','taken_at','created_at','updated_at','date','evaluated_at','submitted_at']);
  $scoreCol   = ec_pick_col($db,'results',['final_marks','final_mark','final_score','score','marks','mark','obtained_marks']);
  $totalCol   = ec_pick_col($db,'results',['total','total_marks','out_of','max_marks']);
  $gradeCol   = ec_pick_col($db,'results',['grade','final_grade']);
  $statusCol  = ec_pick_col($db,'results',['status','result','pass_fail','final_result']);

  if (!$scoreCol) return null;

  $conds = [];
  $types = '';
  $params = [];

  if ($refCol && $refKeys) {
    $ph = implode(',', array_fill(0, count($refKeys), '?'));
    $conds[] = "r.`$refCol` IN ($ph)";
    $types .= str_repeat('s', count($refKeys));
    $params = array_merge($params, $refKeys);
  }

  if ($studentCol) {
    // Prefer exam-system students.id if exists
    if ($exam_students_id) {
      $conds[] = "r.`$studentCol` = ?";
      $types .= 'i';
      $params[] = $exam_students_id;
    }
    // Also allow studentss.id match as fallback
    $conds[] = "r.`$studentCol` = ?";
    $types .= 'i';
    $params[] = $studentss_id;
  }

  if (!$conds) return null;

  $order = [];
  if ($dateCol) $order[] = "COALESCE(r.`$dateCol`, '1970-01-01') DESC";
  $order[] = "r.id DESC";

  $sql = "
    SELECT
      r.id,
      r.exam_id,
      ".($dateCol ? "r.`$dateCol` AS date_taken" : "NULL AS date_taken").",
      r.`$scoreCol` AS score,
      ".($totalCol ? "r.`$totalCol` AS total" : "NULL AS total").",
      ".($gradeCol ? "r.`$gradeCol` AS grade" : "NULL AS grade").",
      ".($statusCol ? "r.`$statusCol` AS status" : "NULL AS status")."
    FROM results r
    WHERE r.exam_id = ?
      AND (" . implode(' OR ', $conds) . ")
    ORDER BY " . implode(', ', $order) . "
    LIMIT 1
  ";

  $st = $db->prepare($sql);
  // prepend exam_id
  $types2 = 'i' . $types;
  $params2 = array_merge([$exam_id], $params);
  $st->bind_param($types2, ...$params2);
  $st->execute();
  $row = stmt_fetch_one_assoc($st);
  $st->close();

  return $row ?: null;
}

/**
 * Build Evaluation Attempts rows for ONE child course using Marks Validation logic.
 * Returns rows like:
 *  module_name, evaluation_method, evaluation_type, date_evaluated, score, total, grade, result
 */
function ec_build_eval_attempts_like_marks_validation(mysqli $db, int $studentss_id, array $studentRow, int $child_course_id, array $refs_for_child = []): array {
  $modules = ec_get_modules_like_marks_validation($db, $child_course_id);
  if (!$modules) return [];

  $refKeys = ec_get_student_ref_keys($studentRow, $refs_for_child);
  $exam_students_id = ec_get_exam_students_id($db, $studentRow, $refs_for_child);

  $out = [];
  foreach ($modules as $m) {
    $unitNo = (int)$m['unit_no'];
    $moduleId = (int)$m['module_id'];
    $title = (string)$m['title'];

    $finalExamId = ec_find_final_exam_id_for_unit($db, $child_course_id, $unitNo, $moduleId);
    $r = $finalExamId ? ec_get_last_result_for_exam($db, $finalExamId, $studentss_id, $refKeys, $exam_students_id) : null;

    $score = $r['score'] ?? null;
    $total = $r['total'] ?? null;
    $grade = $r['grade'] ?? null;
    $status= $r['status'] ?? null;
    $date  = $r['date_taken'] ?? null;

    // derive Pass/Fail if status/grade missing but score exists
    $result = '-';
    if ($status !== null && trim((string)$status) !== '') {
      $result = (string)$status;
    } elseif ($grade !== null && trim((string)$grade) !== '') {
      $result = ec_result_from_grade((string)$grade, (float)$score, (float)$total);
    } elseif ($score !== null && is_numeric($score)) {
      $pct = ($total && (float)$total > 0) ? ((float)$score / (float)$total) * 100.0 : (float)$score;
      $result = ($pct >= 50.0) ? 'Pass' : 'Fail';
    }

    $out[] = [
      'module_name' => $title,
      'evaluation_method' => (stripos($title, 'final project') !== false ? 'Software Project' : 'Online Exam'),
      'evaluation_type' => 'Final',
      'date_evaluated' => ($date && trim((string)$date) !== '') ? (string)$date : '-',
      'score' => $score,
      'total' => $total,
      'grade' => ($grade && trim((string)$grade) !== '') ? (string)$grade : '-',
      'result' => $result ?: '-',
    ];
  }

  return $out;
}



function load_student(mysqli $db, int $sid): array {
  $st = $db->prepare("SELECT * FROM studentss WHERE id=? LIMIT 1");
  $st->bind_param('i', $sid);
  $st->execute();
  $row = stmt_fetch_one_assoc($st);
  $st->close();
  return $row ?: [];
}
function build_academic_email(?array $student, int $sid): string {
  $ref = '';
  if (is_array($student)) {
    $ref = trim((string)(
      $student['reference_no'] ??
      $student['ref_no'] ??
      $student['reference_number'] ?? ''
    ));
  }
  $num = '';
  if ($ref !== '' && preg_match('/(\d{1,10})/', $ref, $m)) { $num = $m[1]; }
  if ($num === '') { $num = (string)$sid; }
  return 'Ec' . $num . '@eden.academy';
}
function compute_outstanding_lkr(mysqli $db, int $sid, int $courseId = 0): float {
  $course = $reg = $late = $disc = 0.0; 
  $extra  = 0.0;

  if (tableExists($db, 'student_fee_plans')) {
    $extraCol = colExists($db,'student_fee_plans','extra_fee_lkr')
      ? 'extra_fee_lkr'
      : (colExists($db,'student_fee_plans','extra_fees_lkr') ? 'extra_fees_lkr' : null);

    $cols = "course_fee_lkr,registration_fee_lkr,late_charges,plan_discount_lkr,manual_discount_lkr,method_discount_lkr";
    $cols .= $extraCol ? ", $extraCol AS extra_fee_lkr" : ", 0 AS extra_fee_lkr";

    if ($courseId > 0 && colExists($db,'student_fee_plans','course_id')) {
      $st = $db->prepare("SELECT $cols FROM student_fee_plans WHERE student_id=? AND course_id=? ORDER BY id DESC LIMIT 1");
      $st->bind_param('ii', $sid, $courseId);
    } else {
      $st = $db->prepare("SELECT $cols FROM student_fee_plans WHERE student_id=? ORDER BY id DESC LIMIT 1");
      $st->bind_param('i', $sid);
    }

    $st->execute();
    $row = method_exists($st,'get_result') ? $st->get_result()->fetch_assoc() : stmt_fetch_one_assoc($st);
    $st->close();

    if ($row) {
      $course = (float)($row['course_fee_lkr'] ?? 0);
      $reg    = (float)($row['registration_fee_lkr'] ?? 0);
      $late   = (float)($row['late_charges'] ?? 0);
      $extra  = (float)($row['extra_fee_lkr'] ?? 0);
      $disc   = (float)($row['plan_discount_lkr'] ?? 0)
              + (float)($row['manual_discount_lkr'] ?? 0)
              + (float)($row['method_discount_lkr'] ?? 0);
    }
  }

  $paid = 0.0;
  if (tableExists($db,'payments')) {
    if ($courseId > 0 && colExists($db,'payments','course_id')) {
      $st = $db->prepare("SELECT SUM(amount) AS s FROM payments WHERE student_id=? AND course_id=?");
      $st->bind_param('ii', $sid, $courseId);
    } elseif ($courseId > 0 && tableExists($db,'student_fee_plans') && colExists($db,'payments','plan_id')) {
      $st = $db->prepare("
        SELECT SUM(p.amount) AS s
        FROM payments p
        JOIN student_fee_plans sfp ON sfp.id = p.plan_id
        WHERE p.student_id=? AND sfp.course_id=?
      ");
      $st->bind_param('ii', $sid, $courseId);
    } else {
      $st = $db->prepare("SELECT SUM(amount) AS s FROM payments WHERE student_id=?");
      $st->bind_param('i', $sid);
    }

    $st->execute();
    $row = method_exists($st,'get_result') ? $st->get_result()->fetch_assoc() : stmt_fetch_one_assoc($st);
    $st->close();
    $paid = (float)($row['s'] ?? 0);
  }

  $total = max(0.0, ($course + $reg - max(0.0, $disc) + $late + $extra));
  return max(0.0, $total - $paid);
}

//===============================
function compute_has_overdue_month(mysqli $db, int $sid, int $courseId = 0): int {
  if (!tableExists($db, 'payment_schedule') || !tableExists($db, 'payments')) return 0;

  $has_schedule_id = colExists($db, 'payments', 'schedule_id');
  $has_sfp = tableExists($db, 'student_fee_plans');

  // overdue = only installments whose due_date has already arrived/passed
  if ($has_schedule_id) {
    $sql = "
      SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS has_overdue
      FROM payment_schedule ps
      " . ($has_sfp ? "JOIN student_fee_plans sfp ON sfp.id = ps.plan_id" : "") . "
      LEFT JOIN (
        SELECT schedule_id, SUM(amount) AS paid_amount
        FROM payments
        WHERE schedule_id IS NOT NULL
        GROUP BY schedule_id
      ) px ON px.schedule_id = ps.id
      WHERE ps.student_id = ?
        " . ($courseId > 0 && $has_sfp ? "AND sfp.course_id = ?" : "") . "
        AND ps.due_date <= CURDATE()
        AND (COALESCE(ps.course_fee_lkr,0) + COALESCE(ps.registration_fee_lkr,0))
            > COALESCE(px.paid_amount,0) + 0.009
    ";

    $st = $db->prepare($sql);
    if (!$st) return 0;

    if ($courseId > 0 && $has_sfp) {
      $st->bind_param('ii', $sid, $courseId);
    } else {
      $st->bind_param('i', $sid);
    }

    $st->execute();
    $row = stmt_fetch_one_assoc($st);
    $st->close();

    return (int)($row['has_overdue'] ?? 0);
  }

  // fallback logic without schedule_id
  $dueSql = "
    SELECT COALESCE(SUM(COALESCE(ps.course_fee_lkr,0) + COALESCE(ps.registration_fee_lkr,0)),0) AS due_lkr
    FROM payment_schedule ps
    " . ($has_sfp ? "JOIN student_fee_plans sfp ON sfp.id = ps.plan_id" : "") . "
    WHERE ps.student_id = ?
      " . ($courseId > 0 && $has_sfp ? "AND sfp.course_id = ?" : "") . "
      AND ps.due_date <= CURDATE()
  ";

  $st = $db->prepare($dueSql);
  if (!$st) return 0;

  if ($courseId > 0 && $has_sfp) {
    $st->bind_param('ii', $sid, $courseId);
  } else {
    $st->bind_param('i', $sid);
  }

  $st->execute();
  $dueRow = stmt_fetch_one_assoc($st);
  $st->close();

  $paidSql = "SELECT COALESCE(SUM(amount),0) AS paid_lkr FROM payments WHERE student_id = ?";

  if ($courseId > 0 && colExists($db, 'payments', 'course_id')) {
    $paidSql = "SELECT COALESCE(SUM(amount),0) AS paid_lkr FROM payments WHERE student_id = ? AND course_id = ?";
    $st = $db->prepare($paidSql);
    if (!$st) return 0;
    $st->bind_param('ii', $sid, $courseId);
  } elseif ($courseId > 0 && $has_sfp && colExists($db, 'payments', 'plan_id')) {
    $paidSql = "
      SELECT COALESCE(SUM(p.amount),0) AS paid_lkr
      FROM payments p
      JOIN student_fee_plans sfp ON sfp.id = p.plan_id
      WHERE p.student_id = ? AND sfp.course_id = ?
    ";
    $st = $db->prepare($paidSql);
    if (!$st) return 0;
    $st->bind_param('ii', $sid, $courseId);
  } else {
    $st = $db->prepare($paidSql);
    if (!$st) return 0;
    $st->bind_param('i', $sid);
  }

  $st->execute();
  $paidRow = stmt_fetch_one_assoc($st);
  $st->close();

  $due_lkr  = (float)($dueRow['due_lkr'] ?? 0);
  $paid_lkr = (float)($paidRow['paid_lkr'] ?? 0);

  return ($due_lkr > $paid_lkr + 0.009) ? 1 : 0;
}




//=================================

function compute_oldest_unpaid_due_date(mysqli $db, int $sid, int $courseId = 0): ?string {
  if (!tableExists($db, 'payment_schedule')) return null;

  $has_sfp        = tableExists($db, 'student_fee_plans');
  $has_schedule_id= tableExists($db, 'payments') && colExists($db, 'payments', 'schedule_id');

  if ($has_schedule_id) {
    $sql = "
      SELECT MIN(ps.due_date) AS oldest_due
      FROM payment_schedule ps
      " . ($has_sfp ? "JOIN student_fee_plans sfp ON sfp.id = ps.plan_id" : "") . "
      LEFT JOIN (
        SELECT schedule_id, SUM(amount) AS paid_amount
        FROM payments
        WHERE schedule_id IS NOT NULL
        GROUP BY schedule_id
      ) px ON px.schedule_id = ps.id
      WHERE ps.student_id = ?
        " . ($courseId > 0 && $has_sfp ? "AND sfp.course_id = ?" : "") . "
        AND ps.due_date <= CURDATE()
        AND (COALESCE(ps.course_fee_lkr,0) + COALESCE(ps.registration_fee_lkr,0))
            > COALESCE(px.paid_amount,0) + 0.009
    ";

    $st = $db->prepare($sql);
    if (!$st) return null;

    if ($courseId > 0 && $has_sfp) {
      $st->bind_param('ii', $sid, $courseId);
    } else {
      $st->bind_param('i', $sid);
    }

    $st->execute();
    $row = stmt_fetch_one_assoc($st);
    $st->close();

    $d = trim((string)($row['oldest_due'] ?? ''));
    return $d !== '' ? $d : null;
  }

  // fallback
  $sql = "
    SELECT MIN(ps.due_date) AS oldest_due
    FROM payment_schedule ps
    " . ($has_sfp ? "JOIN student_fee_plans sfp ON sfp.id = ps.plan_id" : "") . "
    WHERE ps.student_id = ?
      " . ($courseId > 0 && $has_sfp ? "AND sfp.course_id = ?" : "") . "
      AND ps.due_date <= CURDATE()
  ";

  $st = $db->prepare($sql);
  if (!$st) return null;

  if ($courseId > 0 && $has_sfp) {
    $st->bind_param('ii', $sid, $courseId);
  } else {
    $st->bind_param('i', $sid);
  }

  $st->execute();
  $row = stmt_fetch_one_assoc($st);
  $st->close();

  $d = trim((string)($row['oldest_due'] ?? ''));
  return $d !== '' ? $d : null;
}
//==================================


// ==== AJAX: reset password ====
if (($_GET['do'] ?? '') === 'reset_academic') {
  header('Content-Type: application/json');
  try {
    $student = load_student($mysqli, $student_id);
    if (!$student) throw new Exception('Student not found.');

    $academic_email = trim((string)($student['academic_email'] ?? ''));
    if ($academic_email === '') {
      $academic_email = build_academic_email($student, $student_id);
      if (colExists($mysqli, 'studentss', 'academic_email')) {
        $st = $mysqli->prepare("UPDATE studentss SET academic_email=? WHERE id=?");
        $st->bind_param('si', $academic_email, $student_id);
        $st->execute(); $st->close();
      }
    }

    $alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789@#';
    $plain=''; for($i=0;$i<10;$i++){ $plain .= $alphabet[random_int(0, strlen($alphabet)-1)]; }
    $hash = password_hash($plain, PASSWORD_BCRYPT);

    $has_plain   = colExists($mysqli, 'studentss', 'academic_plain_password');
    $has_updated = colExists($mysqli, 'studentss', 'updated_at');

    $has_reset_count = colExists($mysqli, 'studentss', 'academic_reset_count');

$sql = "UPDATE studentss SET academic_password_hash=?";
$types = 's';
$args = [$hash];

if ($has_plain) {
  $sql .= ", academic_plain_password=?";
  $types .= 's';
  $args[] = $plain;
}

if ($has_reset_count) {
  $sql .= ", academic_reset_count = COALESCE(academic_reset_count,0) + 1";
}

if ($has_updated) {
  $sql .= ", updated_at=NOW()";
}

$sql .= " WHERE id=?";
$types .= 'i';
$args[] = $student_id;

    $st = $mysqli->prepare($sql); $st->bind_param($types, ...$args); $st->execute(); $st->close();
    $new_count = 0;
if ($has_reset_count) {
  $stc = $mysqli->prepare("SELECT academic_reset_count FROM studentss WHERE id=? LIMIT 1");
  $stc->bind_param('i', $student_id);
  $stc->execute();
  $rc = stmt_fetch_one_assoc($stc);
  $stc->close();
  $new_count = (int)($rc['academic_reset_count'] ?? 0);
}

echo json_encode([
  'ok' => true,
  'email' => $academic_email,
  'pw' => $has_plain ? $plain : null,
  'reset_count' => $new_count
]);
  } catch (Throwable $e) { http_response_code(500); echo json_encode(['ok'=>false,'message'=>'Failed to reset: '.$e->getMessage()]); }
  exit;
}

// ==== AJAX: create/toggle LMS ====
if (($_GET['do'] ?? '') === 'create_or_toggle_lms') {
  header('Content-Type: application/json');
  try {
    $student = load_student($mysqli, $student_id);
    if (!$student) throw new Exception('Student not found.');
    $out_lkr    = compute_outstanding_lkr($mysqli, $student_id);
    $is_overdue = $out_lkr > 0.00001;

    $academic_email = trim((string)($student['academic_email'] ?? ''));

    // Read current status from lms_status ENUM column
    $has_lms_col = colExists($mysqli, 'studentss', 'lms_status');
    $cur_active  = 1; // default Active
    if ($has_lms_col) {
     $row = $mysqli->query("SELECT lms_status FROM studentss WHERE id=".(int)$student_id)->fetch_assoc();
$raw = strtolower(trim((string)($row['lms_status'] ?? 'active')));
$cur_active = match($raw) { 'inactive' => 0, 'suspended' => 2, default => 1 };
    }

    // Accept target 0, 1, or 2 — do NOT clamp to boolean
    $target_req = isset($_POST['target']) ? (int)$_POST['target'] : null;
    if ($target_req !== null) {
      $target_req = in_array($target_req, [0, 1, 2], true) ? $target_req : 1;
    }
    $override = (int)($_POST['override'] ?? 0) === 1;

    // Helper: int -> ENUM string
    $toEnumVal = fn(int $v): string => match($v) {
      0       => 'Inactive',
      2       => 'Suspended',
      default => 'Active',
    };

    $just_created = false;

    if ($academic_email === '') {
      // First time: create credentials
      $academic_email = build_academic_email($student, $student_id);
      $alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789@#';
      $plain = ''; for ($i=0;$i<10;$i++) { $plain .= $alphabet[random_int(0, strlen($alphabet)-1)]; }
      $hash = password_hash($plain, PASSWORD_BCRYPT);
      $has_plain   = colExists($mysqli, 'studentss', 'academic_plain_password');
      $has_updated = colExists($mysqli, 'studentss', 'updated_at');

      $initial_active = ($target_req !== null) ? $target_req : ($is_overdue ? 0 : 1);
      if ($initial_active === 1 && $is_overdue && !$override) {
        echo json_encode(['ok'=>false,'needs_override'=>true,'message'=>'Outstanding dues — cannot activate. Click again to override.']); exit;
      }

      $enumVal = $toEnumVal($initial_active);
      $sql   = "UPDATE studentss SET academic_email=?, academic_password_hash=?";
      $types = 'ss'; $args = [$academic_email, $hash];
      if ($has_plain)   { $sql .= ", academic_plain_password=?"; $types .= 's'; $args[] = $plain; }
      if ($has_lms_col) { $sql .= ", lms_status=?";              $types .= 's'; $args[] = $enumVal; $cur_active = $initial_active; }
      if ($has_updated) { $sql .= ", updated_at=NOW()"; }
      $sql .= " WHERE id=?"; $types .= 'i'; $args[] = $student_id;

      $st = $mysqli->prepare($sql); $st->bind_param($types, ...$args); $st->execute(); $st->close();
      $just_created = true;
    } else {
      // Toggle or explicit target
      if ($target_req === null) {
        $target = match((int)$cur_active) {
          1       => 0,
          0       => 1,
          default => 1,
        };
      } else {
        $target = $target_req;
      }

      if ($target === 1 && $is_overdue && !$override) {
        echo json_encode(['ok'=>false,'needs_override'=>true,'message'=>'Outstanding dues — cannot activate. Click again to override.']); exit;
      }

      if ($has_lms_col) {
        $enumVal = $toEnumVal($target);
        $st = $mysqli->prepare("UPDATE studentss SET lms_status=? WHERE id=?");
        $st->bind_param('si', $enumVal, $student_id);
        $st->execute(); $st->close();
        $cur_active = $target;
      }
    }

    echo json_encode(['ok'=>true,'email'=>$academic_email,'active'=>(int)$cur_active,'just_created'=>$just_created,'overdue'=>$is_overdue]);
  } catch (Throwable $e) {
    http_response_code(500);
    echo json_encode(['ok'=>false,'message'=>'Failed to create/toggle: '.$e->getMessage()]);
  }
  exit;
}

// ==== LOAD STUDENT + DATA ====
$st = $mysqli->prepare("SELECT * FROM studentss WHERE id=? LIMIT 1");
$st->bind_param("i",$student_id); $st->execute();
$student = stmt_fetch_one_assoc($st); $st->close();
if (!$student) { die("Student not found."); }

$center_reg_no = $student['center_reg_no'] ?? $student['center_registration_no'] ?? $student['center_no'] ?? $student['center_reg'] ?? '';
$reference_no  = $student['reference_no'] ?? $student['ref_no'] ?? $student['reference_number'] ?? '';

$has_lms_active = colExists($mysqli,'studentss','lms_status');
$lms_active = 1; // 1=Active, 0=Inactive, 2=Suspended
if ($has_lms_active) {
  $row = $mysqli->query("SELECT lms_status FROM studentss WHERE id=".(int)$student_id)->fetch_assoc();
  $raw = strtolower(trim((string)($row['lms_status'] ?? 'active')));
  $lms_active = match($raw) {
    'inactive'  => 0,
    'suspended' => 2,
    default     => 1,
  };
}
$academic_email = trim((string)($student['academic_email'] ?? ''));
$academic_hash  = trim((string)($student['academic_password_hash'] ?? ''));
$academic_plain_password = isset($student['academic_plain_password']) ? trim((string)$student['academic_plain_password']) : '';
$academic_reset_count = (int)($student['academic_reset_count'] ?? 0);
$student_mobile = trim((string)($student['mobile'] ?? ''));
$created_on     = (string)($student['created_at'] ?? '');
$ref_no         = trim((string)($student['reference_no'] ?? ''));

$promotion_plan = '';

// ==== Resolve course context correctly ====
// Priority:
// 1) explicit ?course_id
// 2) latest course that already has payments
// 3) latest fee plan course_id
// 4) latest enrolled batch course_id
// 5) studentss.course_id fallback

$resolved_course_id = 0;

// 1) explicit course_id from request
if ($course_id > 0) {
  $resolved_course_id = $course_id;
}

// 2) latest payment-bearing course
if (
  $resolved_course_id <= 0 &&
  tableExists($mysqli,'payments') &&
  colExists($mysqli,'payments','course_id')
) {
  $st = $mysqli->prepare("
    SELECT course_id
    FROM payments
    WHERE student_id=? AND course_id IS NOT NULL AND course_id > 0
    ORDER BY date_paid DESC, id DESC
    LIMIT 1
  ");
  $st->bind_param("i", $student_id);
  $st->execute();
  $row = stmt_fetch_one_assoc($st);
  $st->close();

  if (!empty($row['course_id'])) {
    $resolved_course_id = (int)$row['course_id'];
  }
}

// 3) latest student fee plan course
if (
  $resolved_course_id <= 0 &&
  tableExists($mysqli,'student_fee_plans') &&
  colExists($mysqli,'student_fee_plans','course_id')
) {
  $st = $mysqli->prepare("
    SELECT course_id
    FROM student_fee_plans
    WHERE student_id=? AND course_id IS NOT NULL AND course_id > 0
    ORDER BY id DESC
    LIMIT 1
  ");
  $st->bind_param("i", $student_id);
  $st->execute();
  $row = stmt_fetch_one_assoc($st);
  $st->close();

  if (!empty($row['course_id'])) {
    $resolved_course_id = (int)$row['course_id'];
  }
}

// 4) latest enrolled batch course
if (
  $resolved_course_id <= 0 &&
  tableExists($mysqli,'enrollments') &&
  tableExists($mysqli,'batches')
) {
  $st = $mysqli->prepare("
    SELECT b.course_id
    FROM enrollments e
    JOIN batches b ON b.id = e.batch_id
    WHERE e.student_id = ?
    ORDER BY e.id DESC
    LIMIT 1
  ");
  $st->bind_param("i",$student_id);
  $st->execute();
  $row = stmt_fetch_one_assoc($st);
  $st->close();

  if (!empty($row['course_id'])) {
    $resolved_course_id = (int)$row['course_id'];
  }
}

// 5) fallback only
if ($resolved_course_id <= 0) {
  $resolved_course_id = (int)($student['course_id'] ?? 0);
}

/* normalize course filter array AFTER resolved course is known */
$filter_course_ids = $resolved_course_id > 0 ? [$resolved_course_id] : [];

/** Child-course scope for filtering refs + batches based on selected/resolved course */
$scope_child_ids = [];
if ($filter_course_ids) {
  $tmp = array_map('intval', $filter_course_ids);

  if (tableExists($mysqli,'course_children')) {
    $in = implode(',', $tmp);
    $map = [];

    if ($in) {
      $rs = $mysqli->query("SELECT parent_id, child_id FROM course_children WHERE parent_id IN ($in)");
      if ($rs) {
        while ($r = $rs->fetch_assoc()) {
          $map[(int)$r['parent_id']][] = (int)$r['child_id'];
        }
        $rs->free();
      }
    }

    foreach ($tmp as $cid) {
      if (!empty($map[$cid])) {
        $scope_child_ids = array_merge($scope_child_ids, $map[$cid]);
      } else {
        $scope_child_ids[] = $cid; // single course
      }
    }
  } else {
    $scope_child_ids = $tmp;
  }
}

$scope_child_ids = array_values(array_unique(array_filter($scope_child_ids)));

// Course row
$course = [];
if ($resolved_course_id > 0) {
  $st = $mysqli->prepare("
    SELECT *
    FROM courses
    WHERE id = ?
    LIMIT 1
  ");
  $st->bind_param("i", $resolved_course_id);
  $st->execute();
  $course = stmt_fetch_one_assoc($st);
  $st->close();
}



// Per-course EC numbers
$bundle_children = [];
$refs_by_course = [];
if (tableExists($mysqli, 'student_numbers')) {
  $st = $mysqli->prepare("SELECT course_id, reference_no, reference_no2 FROM student_numbers WHERE student_id=?");
$st->bind_param('i', $student_id); $st->execute();
if (method_exists($st, 'get_result')) {
  $rs = $st->get_result();
  while ($r = $rs->fetch_assoc()) {
    $cid = (int)($r['course_id'] ?? 0);
    $refs_by_course[$cid] = [
      'ec1' => trim((string)($r['reference_no']  ?? '')),
      'ec2' => trim((string)($r['reference_no2'] ?? '')),
    ];
  }
} else {
  foreach (stmt_fetch_all_assoc($st) as $r) {
    $cid = (int)($r['course_id'] ?? 0);
    $refs_by_course[$cid] = [
      'ec1' => trim((string)($r['reference_no']  ?? '')),
      'ec2' => trim((string)($r['reference_no2'] ?? '')),
    ];
  }
}
$st->close();


}

// === Build course chips for EVERYTHING the student is doing (two singles or bundle) ===
$bundle_children = [];

// 1) collect distinct course_ids from enrollments (preferred)
$enrolled_course_ids = [];

if ($course_id > 0) {
  $enrolled_course_ids[] = (int)$course_id;
}

if (tableExists($mysqli,'enrollments') && tableExists($mysqli,'batches')) {
  $st = $mysqli->prepare("
    SELECT DISTINCT b.course_id
    FROM enrollments e
    JOIN batches b ON b.id = e.batch_id
    WHERE e.student_id = ?
  ");
  $st->bind_param('i', $student_id);
  $st->execute();

  if (method_exists($st,'get_result')) {
    $rs = $st->get_result();
    while ($r = $rs->fetch_assoc()) $enrolled_course_ids[] = (int)$r['course_id'];
  } else {
    foreach (stmt_fetch_all_assoc($st) as $r) $enrolled_course_ids[] = (int)$r['course_id'];
  }
  $st->close();
}

if ($resolved_course_id > 0) {
  $enrolled_course_ids[] = (int)$resolved_course_id;
}

$enrolled_course_ids = array_values(array_unique(array_filter($enrolled_course_ids)));

// If a specific course was requested, start with just that.
if ($resolved_course_id > 0) {
  $enrolled_course_ids = [$resolved_course_id];
} else {
  // fallback to your existing logic
  if (tableExists($mysqli,'enrollments') && tableExists($mysqli,'batches')) {
    $st = $mysqli->prepare("
      SELECT DISTINCT b.course_id
        FROM enrollments e
        JOIN batches b ON b.id = e.batch_id
       WHERE e.student_id = ?
    ");
    $st->bind_param('i', $student_id);
    $st->execute();
    if (method_exists($st,'get_result')) {
      $rs = $st->get_result();
      while ($r = $rs->fetch_assoc()) $enrolled_course_ids[] = (int)$r['course_id'];
    } else {
      foreach (stmt_fetch_all_assoc($st) as $r) $enrolled_course_ids[] = (int)$r['course_id'];
    }
    $st->close();
  }

  if ($resolved_course_id > 0) $enrolled_course_ids[] = (int)$resolved_course_id;
}

$enrolled_course_ids = array_values(array_unique(array_filter($enrolled_course_ids)));


// always include fallback resolved course
if ($resolved_course_id > 0) $enrolled_course_ids[] = (int)$resolved_course_id;
$enrolled_course_ids = array_values(array_unique(array_filter($enrolled_course_ids)));

// 2) if we have enrolled courses, expand each: bundle parent → children; single → itself
$ids_for_display = [];
if ($enrolled_course_ids) {
  if (tableExists($mysqli,'course_children')) {
    $in = implode(',', array_map('intval', $enrolled_course_ids));
    $map = [];
    if ($in) {
      $res = $mysqli->query("SELECT parent_id, child_id FROM course_children WHERE parent_id IN ($in)");
      if ($res) { while ($row = $res->fetch_assoc()) $map[(int)$row['parent_id']][] = (int)$row['child_id']; $res->free(); }
    }
    foreach ($enrolled_course_ids as $cid) {
      if (!empty($map[$cid])) $ids_for_display = array_merge($ids_for_display, $map[$cid]);
      else $ids_for_display[] = $cid;
    }
  } else {
    $ids_for_display = $enrolled_course_ids;
  }
}
$ids_for_display = array_values(array_unique($ids_for_display));


  // 3) build the chip objects
  $bundle_children = [];
  $st = $mysqli->prepare("SELECT id, course_name, code FROM courses WHERE id=? LIMIT 1");
  foreach ($ids_for_display as $cid) {
    $st->bind_param('i', $cid);
    $st->execute();
    $row = stmt_fetch_one_assoc($st);
    $label = trim((string)($row['code'] ?? '')) ?: trim((string)($row['course_name'] ?? 'Course'));
    $bundle_children[] = [
      'id' => (int)$cid,
      'label' => $label,
      'course_name' => $row['course_name'] ?? '',
      'code' => $row['code'] ?? ''
    ];
  }
  $st->close();


// 4) final fallback if nothing found at all
if (!$bundle_children) {
  $bundle_children = [[
    'id' => (int)$resolved_course_id,
    'label' => $course['code'] ?? ($course['course_name'] ?? ($course['name'] ?? 'Course')),
    'course_name' => $course['course_name'] ?? ($course['name'] ?? '')
  ]];
}



/* ===== Final Exams per Unit (per course) =====
 *  - $finalExamsByCourse[course_id] = [ exam attempt rows... ]
 *  - Each row is one attempt of a “Unit XX - Final Exam” from `results`
 */
$finalExamsByCourse = [];

if (
    $student_id > 0 &&
    tableExists($mysqli, 'exams') &&
    tableExists($mysqli, 'results')
) {
    // unified reference (covers reference_no / ref_no / reference_number)
    $ref_key = trim((string)(
        $student['reference_no']     ??
        $student['ref_no']           ??
        $student['reference_number'] ??
        ''
    ));

    // which courses we are showing as chips
    $examCourseIds = array_map('intval', $ids_for_display ?: []);
    if (!$examCourseIds && $resolved_course_id > 0) {
        $examCourseIds = [(int)$resolved_course_id];
    }
    $examCourseIds = array_values(array_unique(array_filter($examCourseIds)));

    if ($examCourseIds) {
        $inCourses = implode(',', $examCourseIds);

        // decide which reference column to use
        $refCol = null;
        foreach (['reference_no','ref_no','student_ref_no'] as $c) {
            if (colExists($mysqli, 'results', $c)) {
                $refCol = $c;
                break;
            }
        }

        $conds  = [];
        $types  = '';
        $params = [];

        if ($refCol && $ref_key !== '') {
            $conds[]  = "r.$refCol = ?";
            $types   .= 's';
            $params[] = $ref_key;
        }

        if (colExists($mysqli, 'results', 'student_id')) {
            $conds[]  = "r.student_id = ?";
            $types   .= 'i';
            $params[] = $student_id;
        }

        // if nothing to match on, don't return anything
        $whereResults = $conds ? '(' . implode(' OR ', $conds) . ')' : '1=0';

        // only FINAL exams, based on module_name
$finalParts = [];
if (colExists($mysqli,'results','module_name')) $finalParts[] = "LOWER(COALESCE(r.module_name,'')) LIKE '%final%'";
if (colExists($mysqli,'exams','unit_exam'))    $finalParts[] = "LOWER(COALESCE(e.unit_exam,'')) LIKE '%final%'";
if (colExists($mysqli,'exams','title'))        $finalParts[] = "LOWER(COALESCE(e.title,'')) LIKE '%final%'";
if (colExists($mysqli,'exams','type'))         $finalParts[] = "LOWER(COALESCE(e.type,'')) LIKE '%final%'";

$finalFilter = $finalParts ? " AND (" . implode(" OR ", $finalParts) . ")" : "";



        // optional units table for nicer titles
        $has_units   = tableExists($mysqli, 'units');
        $joinUnits   = $has_units ? 'LEFT JOIN units u ON u.id = e.unit_id' : '';
        $selectUnit  = $has_units ? 'u.name AS unit_title,' : "NULL AS unit_title,";

        $orderBy = colExists($mysqli, 'exams', 'unit_id')
            ? 'ORDER BY e.course_id, e.unit_id, r.date_taken DESC, r.id DESC'
            : 'ORDER BY e.course_id, r.date_taken DESC, r.id DESC';

        $sql = "
  SELECT
    e.course_id,
    e.id AS exam_id,
    COALESCE(NULLIF(TRIM(e.unit_exam),''), NULLIF(TRIM(e.title),''), NULLIF(TRIM(r.module_name),''), 'Exam') AS module_name,
    r.score,
    r.total,
    r.grade,
    r.date_taken AS when_taken,
    r.id AS result_id
  FROM results r
  JOIN exams e ON e.id = r.exam_id
  $joinUnits
  WHERE
    $whereResults
    AND e.course_id IN ($inCourses)
    $finalFilter
  $orderBy
";


        if ($st = $mysqli->prepare($sql)) {
            if ($types !== '' && !empty($params)) {
                $st->bind_param($types, ...$params);
            }
            $st->execute();

            // ✅ NEW: keep *all* attempts per course, no per-unit dedupe
            if (method_exists($st, 'get_result')) {
                $res = $st->get_result();
                while ($row = $res->fetch_assoc()) {
                    $cid = (int)($row['course_id'] ?? 0);
                    if ($cid <= 0) continue;

                    $finalExamsByCourse[$cid][] = $row;
                }
            } else {
                foreach (stmt_fetch_all_assoc($st) as $row) {
                    $cid = (int)($row['course_id'] ?? 0);
                    if ($cid <= 0) continue;

                    $finalExamsByCourse[$cid][] = $row;
                }
            }

            $st->close();
        }
    }
}
$eval_by_course = ec_collapse_latest_exam_per_module($eval_by_course ?? []);



// Lesson plan by child
$child_lessons = [];
foreach ($bundle_children as $bc) {
    $cid = (int)$bc['id'];
    $titles = [];

    $st = $mysqli->prepare("SELECT modules FROM courses WHERE id=? LIMIT 1");
    $st->bind_param('i', $cid);
    $st->execute();
    if (method_exists($st, 'get_result')) {
        $row = $st->get_result()->fetch_assoc();
    } else {
        $row = stmt_fetch_one_assoc($st);
    }
    $mod = $row['modules'] ?? null;
    $st->close();

    if ($mod) {
        $j = json_decode($mod, true);
        if (is_array($j)) {
            foreach ($j as $row2) {
                $t = is_array($row2) ? trim((string)($row2['title'] ?? $row2['name'] ?? '')) : trim((string)$row2);
                if ($t !== '') $titles[] = $t;
            }
        } else {
            foreach (explode(',', (string)$mod) as $t) {
                $t = trim($t);
                if ($t !== '') $titles[] = $t;
            }
        }
    }

    if (!$titles && tableExists($mysqli,'course_modules')) {
        $st = $mysqli->prepare("SELECT title FROM course_modules WHERE course_id=? ORDER BY sort_order ASC, id ASC");
        $st->bind_param('i', $cid);
        $st->execute();
        if (method_exists($st, 'get_result')) {
            $rs = $st->get_result();
            while ($r = $rs->fetch_assoc()) {
                $t = trim((string)($r['title'] ?? ''));
                if ($t !== '') $titles[] = $t;
            }
        } else {
            foreach (stmt_fetch_all_assoc($st) as $r) {
                $t = trim((string)($r['title'] ?? ''));
                if ($t !== '') $titles[] = $t;
            }
        }
        $st->close();
    }

    $child_lessons[$cid] = $titles;
}

/* ==== EVALUATIONS PLAN / FINAL EXAMS (latest per module/exam, per course) ====
 *  - Reads from `results` (+ optional `exams`) tables
 *  - Buckets per course/unit (bundle-safe)
 *  - If we can’t reliably detect “final”, we show ALL exams instead of nothing.
 */
$eval_by_course = [];
$eval_rows      = [];

if (tableExists($mysqli, 'results')) {

    // unified reference (covers reference_no / ref_no / reference_number)
    $ref_key = trim((string)(
        $student['reference_no']     ??
        $student['ref_no']           ??
        $student['reference_number'] ??
        ''
    ));

        // --- build a *single* safe WHERE condition (REFERENCE and/or STUDENT ID) ----------
    $types    = '';
    $params   = [];
    $whereSql = '1=0'; // default → no rows unless we have a usable condition

    $refCol = null;
    foreach (['reference_no','ref_no','student_ref_no'] as $col) {
        if (colExists($mysqli, 'results', $col)) {
            $refCol = $col;
            break;
        }
    }

    $conds = [];

    if ($refCol && $ref_key !== '') {
        $conds[]  = 'r.' . $refCol . ' = ?';
        $types   .= 's';
        $params[] = $ref_key;
    }

    if (colExists($mysqli, 'results', 'student_id')) {
        $conds[]  = 'r.student_id = ?';
        $types   .= 'i';
        $params[] = $student_id;
    }

    if ($conds) {
        $whereSql = '(' . implode(' OR ', $conds) . ')';
    }

    // If we found no usable condition at all, there is nothing safe to query
    if ($whereSql !== '1=0') {


        $has_exams     = tableExists($mysqli, 'exams');
        $has_r_date    = colExists($mysqli, 'results', 'date_taken');
        $has_r_modname = colExists($mysqli, 'results', 'module_name');
        $has_r_score   = colExists($mysqli, 'results', 'score');
        $has_r_total   = colExists($mysqli, 'results', 'total');
        $has_r_grade   = colExists($mysqli, 'results', 'grade');
        $has_r_course  = colExists($mysqli, 'results', 'course_id');

        $has_e_type    = $has_exams ? colExists($mysqli, 'exams', 'type')      : false;
        $has_e_title   = $has_exams ? colExists($mysqli, 'exams', 'title')     : false;
        $has_e_unit    = $has_exams ? colExists($mysqli, 'exams', 'unit_exam') : false;
        $has_e_course  = $has_exams ? colExists($mysqli, 'exams', 'course_id') : false;

// ==== FINAL EXAMS ONLY FILTER ====
// Treat as "final" if ANY meaningful label column contains "final"
// (this includes exams.unit_exam which your current code misses)

$finalCols = [];

if ($has_r_modname) $finalCols[] = "r.module_name";
if ($has_e_unit)    $finalCols[] = "e.unit_exam";
if ($has_e_title)   $finalCols[] = "e.title";
if ($has_e_type)    $finalCols[] = "e.type";

$finalSQL = '';
if ($finalCols) {
    $finalParts = [];

    if ($has_r_modname) $finalParts[] = "LOWER(COALESCE(r.module_name,'')) LIKE '%final%'";
    if ($has_e_unit)    $finalParts[] = "LOWER(COALESCE(e.unit_exam,'')) LIKE '%final%'";
    if ($has_e_title)   $finalParts[] = "LOWER(COALESCE(e.title,'')) LIKE '%final%'";
    if ($has_e_type)    $finalParts[] = "LOWER(COALESCE(e.type,'')) LIKE '%final%'";

    $finalSQL = $finalParts ? " AND (" . implode(" OR ", $finalParts) . ")" : "";
} // ✅ <-- MISSING in your pasted file




        // Use date_taken if available, otherwise the row id
        $dateR = $has_r_date ? 'r.date_taken' : 'r.id';

        // Human-readable label for the module / unit
        $labelExpr = [];
if ($has_e_unit)    $labelExpr[] = "NULLIF(TRIM(e.unit_exam),'')";
if ($has_e_title)   $labelExpr[] = "NULLIF(TRIM(e.title),'')";
if ($has_r_modname) $labelExpr[] = "NULLIF(TRIM(r.module_name),'')";

$labelSQL = $labelExpr
  ? 'COALESCE(' . implode(',', $labelExpr) . ", 'Exam')"
  : "'Exam'";


        $selectParts   = [];
        $selectParts[] = "$labelSQL AS module_name";
        $selectParts[] = $has_r_score ? 'r.score' : '0 AS score';
        $selectParts[] = $has_r_total ? 'r.total' : '0 AS total';
        $selectParts[] = $has_r_grade ? 'r.grade' : "'' AS grade";
        $selectParts[] = "$dateR AS when_taken";

        // Course id detection – works whether it lives on exams or results
        $courseIdExpr = '0';
        if ($has_e_course && $has_r_course) {
            $courseIdExpr = 'COALESCE(e.course_id, r.course_id, 0)';
        } elseif ($has_e_course) {
            $courseIdExpr = 'COALESCE(e.course_id, 0)';
        } elseif ($has_r_course) {
            $courseIdExpr = 'COALESCE(r.course_id, 0)';
        }
        $selectParts[] = "$courseIdExpr AS exam_course_id";

        // exam id (if you ever need it)
        $selectParts[] = ($has_exams ? 'COALESCE(r.exam_id,0)' : '0') . ' AS exid';

        $selectCommon = implode(",\n  ", $selectParts);

        $orderBySql = $has_e_unit
    ? 'ORDER BY e.unit_exam ASC, when_taken DESC'
    : 'ORDER BY module_name ASC, when_taken DESC';

// $finalSQL was already built from $finalFilterParts above.
// Do NOT override it here.

$sqlMain = "
  SELECT
    $selectCommon
  FROM results r
  " . ($has_exams ? "LEFT JOIN exams e ON e.id = r.exam_id" : "") . "
  WHERE $whereSql
  $finalSQL
  $orderBySql
";



        $rows = [];
if ($st = $mysqli->prepare($sqlMain)) {
    $st->bind_param($types, ...$params);
    $st->execute();
    $rows = stmt_fetch_all_assoc($st);
    $st->close();
}

// ✅ Fallback: if the "final" filter produced nothing, re-run WITHOUT finalSQL
if (empty($rows) && $finalSQL !== '') {
    $sqlMainAll = "
      SELECT
        $selectCommon
      FROM results r
      " . ($has_exams ? "LEFT JOIN exams e ON e.id = r.exam_id" : "") . "
      WHERE $whereSql
      $orderBySql
    ";

    if ($st = $mysqli->prepare($sqlMainAll)) {
        $st->bind_param($types, ...$params);
        $st->execute();
        $rows = stmt_fetch_all_assoc($st);
        $st->close();
    }
}


        // Bucket rows by COURSE (critical for bundles)
        $child_ids = array_map(function ($c) {
            return (int)($c['id'] ?? 0);
        }, $bundle_children);

        $default_cid = in_array((int)$resolved_course_id, $child_ids, true)
            ? (int)$resolved_course_id
            : ($child_ids[0] ?? 0);

        foreach ($rows as $row) {
            $moduleName = (string)($row['module_name'] ?? 'Exam');

            $one = [
                'module_name' => $moduleName,
                'score'       => (float)($row['score'] ?? 0),
                'total'       => (float)($row['total'] ?? 0),
                'grade'       => (string)($row['grade'] ?? ''),
                'when_taken'  => (string)($row['when_taken'] ?? ''),
            ];

            $examCourseId   = (int)($row['exam_course_id'] ?? 0);
            $cid_for_bucket = 0;

            // Normal case – direct course_id match
            if ($examCourseId && in_array($examCourseId, $child_ids, true)) {
                $cid_for_bucket = $examCourseId;
            }

            // Bundle fallback – map "Unit 01 / 02 / ..." to N-th child course
            if (!$cid_for_bucket && $child_ids && preg_match('/\bUnit\s*0*([0-9]+)\b/i', $moduleName, $m)) {
                $idx = (int)$m[1]; // 1-based
                if ($idx >= 1 && $idx <= count($child_ids)) {
                    $cid_for_bucket = $child_ids[$idx - 1];
                }
            }

            // Final fallback – drop into the default course
            if (!$cid_for_bucket) {
                $cid_for_bucket = $default_cid;
            }

            $eval_by_course[$cid_for_bucket][] = $one;

            // flat list if needed elsewhere
            $eval_rows[] = [
                'module' => $one['module_name'],
                'score'  => $one['score'],
                'total'  => $one['total'],
                'grade'  => $one['grade'],
                'date'   => $one['when_taken'],
            ];
        }
    }
}

// Use the child-course scope for batch filtering
$course_filter_sql = '';
if (!empty($scope_child_ids) && tableExists($mysqli,'batches') && colExists($mysqli,'batches','course_id')) {
    $in = implode(',', array_map('intval', $scope_child_ids));
    $course_filter_sql = " AND b.course_id IN ($in) ";
}



// ==== BATCHES ====
$batches = [];

if (
  tableExists($mysqli,'enrollments') &&
  tableExists($mysqli,'batches') &&
  colExists($mysqli,'enrollments','batch_id')
) {
  $st = $mysqli->prepare("
  SELECT DISTINCT b.id,
         b.status,
         b.batch_code,
         COALESCE(NULLIF(TRIM(b.batch_name),''), 'Batch') AS batch_name
  FROM enrollments e
  JOIN batches b ON b.id = e.batch_id
  WHERE e.student_id = ? {$course_filter_sql}
  ORDER BY b.id ASC
");
  $st->bind_param("i", $student_id);
  $st->execute();
  $batches = stmt_fetch_all_assoc($st);
  $st->close();
}

if (!$batches && tableExists($mysqli,'student_batches') && tableExists($mysqli,'batches')) {
  $st = $mysqli->prepare("
  SELECT DISTINCT b.id,
         b.status,
         b.batch_code,
         COALESCE(NULLIF(TRIM(b.batch_name),''), 'Batch') AS batch_name
  FROM student_batches sb
  JOIN batches b ON b.id = sb.batch_id
  WHERE sb.student_id = ? {$course_filter_sql}
  ORDER BY b.id ASC
");
  $st->bind_param("i", $student_id);
  $st->execute();
  $batches = stmt_fetch_all_assoc($st);
  $st->close();
}

if (!$batches && tableExists($mysqli,'batch_students') && tableExists($mysqli,'batches')) {
  $st = $mysqli->prepare("
  SELECT DISTINCT b.id,
         b.status,
         b.batch_code,
         COALESCE(NULLIF(TRIM(b.batch_name),''), 'Batch') AS batch_name
  FROM batch_students bs
  JOIN batches b ON b.id = bs.batch_id
  WHERE bs.student_id = ? {$course_filter_sql}
  ORDER BY b.id ASC
");
  $st->bind_param("i", $student_id);
  $st->execute();
  $batches = stmt_fetch_all_assoc($st);
  $st->close();
}

// Deduplicate batches by batch_code so the same code is not shown twice
if (!empty($batches)) {
    $unique = [];
    $seen   = [];

    foreach ($batches as $row) {
        $code = strtolower(trim((string)($row['batch_code'] ?? '')));
        // fall back to id if there is no code (should be rare)
        $key  = $code !== '' ? $code : (string)((int)($row['id'] ?? 0));

        if (isset($seen[$key])) {
            continue; // skip duplicate code
        }
        $seen[$key] = true;
        $unique[]   = $row;
    }

    $batches = $unique;
}

// Use the last unique batch (for letters etc.)
$last_batch_id = null;
if (!empty($batches)) {
    $last = end($batches);
    $last_batch_id = (int)($last['id'] ?? 0);
}


// ==== Payment method label ====
$selected_method_raw = '';
if (tableExists($mysqli,'student_fee_plans')) {
  foreach (['payment_method','discount_method','pay_method','method'] as $c) {
    if (!colExists($mysqli,'student_fee_plans',$c)) continue;
    $st = $mysqli->prepare("SELECT `$c` AS m FROM student_fee_plans WHERE student_id=? ORDER BY id DESC LIMIT 1");
    $st->bind_param('i',$student_id);
    $st->execute();
    $r = method_exists($st,'get_result') ? $st->get_result()->fetch_assoc() : stmt_fetch_one_assoc($st);
    $st->close();

    $selected_method_raw = trim((string)($r['m'] ?? ''));
    if ($selected_method_raw !== '') break;
  }
}

if ($selected_method_raw === '' && tableExists($mysqli,'payments')) {
  $st = $mysqli->prepare("SELECT payment_method FROM payments WHERE student_id=? ORDER BY date_paid DESC, id DESC LIMIT 1");
  $st->bind_param('i',$student_id); $st->execute();
  $r = stmt_fetch_one_assoc($st); $st->close();
  $selected_method_raw = trim((string)($r['payment_method'] ?? ''));
}
$method_map = [
  'cash'=>'Cash','bank'=>'Bank Transfer','bank_transfer'=>'Bank Transfer','card'=>'Card',
  'card_visa'=>'Card (Visa/Master)','visa'=>'Card (Visa/Master)','master'=>'Card (Visa/Master)',
  'amex'=>'Card (Amex)','online'=>'Online','one'=>'One-time','one-time'=>'One-time','installment'=>'Installments'
];
$key = strtolower(preg_replace('/\s+/', '_', $selected_method_raw));
$selected_method = $method_map[$key] ?? ($selected_method_raw ?: '-');

// ==== Plan + installments ====
$plan = []; $installments = [];
$has_sfp = tableExists($mysqli,'student_fee_plans');
$has_ps  = tableExists($mysqli,'payment_schedule');

if ($has_sfp) {
  if ($filter_course_ids && colExists($mysqli,'student_fee_plans','course_id')) {
    $in = implode(',', array_map('intval', $filter_course_ids));
    $sql = "SELECT * FROM student_fee_plans WHERE student_id=? AND course_id IN ($in) ORDER BY id DESC LIMIT 1";
    $st  = $mysqli->prepare($sql);
    $st->bind_param("i",$student_id);
  } else {
    $st  = $mysqli->prepare("SELECT * FROM student_fee_plans WHERE student_id=? ORDER BY id DESC LIMIT 1");
    $st->bind_param("i",$student_id);
  }
  $st->execute(); $sfp = stmt_fetch_one_assoc($st); $st->close();
}

if (!empty($sfp)) {
  foreach (['promotion_plan','promo_plan','promotion','promotion_name','promo_name','discount_plan','offer_name'] as $c) {
    if (array_key_exists($c, $sfp) && trim((string)$sfp[$c]) !== '') { $promotion_plan = trim((string)$sfp[$c]); break; }
  }
}
if ($sfp) {
  $plan = [
    'id'                   => is_numeric($sfp['plan_id'] ?? '') ? (int)$sfp['plan_id'] : null,
    'plan_type'            => strtolower((string)($sfp['plan_type'] ?? '')),
    'plan_name'            => $sfp['plan_name'] ?? '',
    'course_fee_lkr'       => (float)($sfp['course_fee_lkr'] ?? 0),
    'registration_fee_lkr' => (float)($sfp['registration_fee_lkr'] ?? 0),
    'certificate_fee_usd'  => (float)($sfp['certificate_fee_usd'] ?? 0),
    'late_charges'         => (float)($sfp['late_charges'] ?? 0),
  ];
if ($has_ps) {
  $has_plan_id = colExists($mysqli,'payment_schedule','plan_id');
  $has_ps_cid  = colExists($mysqli,'payment_schedule','course_id');

  if (!empty($sfp) && $has_plan_id) {
    $st = $mysqli->prepare("
      SELECT installment_no, due_date,
             COALESCE(course_fee_lkr,0)        AS course_fee_lkr,
             COALESCE(registration_fee_lkr,0)  AS registration_fee_lkr,
             COALESCE(certificate_fee_usd,0)   AS certificate_fee_usd
        FROM payment_schedule
       WHERE plan_id=?
       ORDER BY installment_no ASC, id ASC");
    $pid = (int)$sfp['id'];
    $st->bind_param("i",$pid);
  } elseif ($has_ps_cid && $filter_course_ids) {
    $in = implode(',', array_map('intval', $filter_course_ids));
    $st = $mysqli->prepare("
      SELECT installment_no, due_date,
             COALESCE(course_fee_lkr,0)        AS course_fee_lkr,
             COALESCE(registration_fee_lkr,0)  AS registration_fee_lkr,
             COALESCE(certificate_fee_usd,0)   AS certificate_fee_usd
        FROM payment_schedule
       WHERE student_id=? AND course_id IN ($in)
       ORDER BY installment_no ASC, id ASC");
    $st->bind_param("i",$student_id);
  } else {
    $st = $mysqli->prepare("
      SELECT installment_no, due_date,
             COALESCE(course_fee_lkr,0)        AS course_fee_lkr,
             COALESCE(registration_fee_lkr,0)  AS registration_fee_lkr,
             COALESCE(certificate_fee_usd,0)   AS certificate_fee_usd
        FROM payment_schedule
       WHERE student_id=?
       ORDER BY installment_no ASC, id ASC");
    $st->bind_param("i",$student_id);
  }

  $st->execute(); $installments = stmt_fetch_all_assoc($st); $st->close();
}

} else {
  if ($resolved_course_id>0 && tableExists($mysqli,'payment_plans')) {
    $st = $mysqli->prepare("SELECT * FROM payment_plans WHERE course_id=? AND (status='Active' OR status IS NULL) ORDER BY id ASC LIMIT 1");
    $st->bind_param("i",$resolved_course_id); $st->execute();
    $plan = stmt_fetch_one_assoc($st); $st->close();
    if (!empty($plan['id']) && tableExists($mysqli,'installments')) {
      $st = $mysqli->prepare("
        SELECT installment_no, due_date, course_fee_lkr, registration_fee_lkr, certificate_fee_usd
          FROM installments
         WHERE plan_id=?
         ORDER BY installment_no ASC, id ASC");
      $st->bind_param("i",$plan['id']); $st->execute();
      $installments = stmt_fetch_all_assoc($st); $st->close();
    }
  }
}

$sumC=0.0; $sumR=0.0; $sumU=0.0;
foreach ($installments as $ins) { $sumC+=(float)($ins['course_fee_lkr']??0); $sumR+=(float)($ins['registration_fee_lkr']??0); $sumU+=(float)($ins['certificate_fee_usd']??0); }

$course_fee_lkr = (float)($plan['course_fee_lkr'] ?? 0);
$reg_fee_lkr    = (float)($plan['registration_fee_lkr'] ?? 0);
$cert_fee_usd   = (float)($plan['certificate_fee_usd'] ?? 0);
$late_charges   = (float)($plan['late_charges'] ?? 0);
$extra_fee_lkr = 0.0;
if (isset($sfp['extra_fee_lkr'])) {
  $extra_fee_lkr = (float)$sfp['extra_fee_lkr'];
}

$ptype = strtolower((string)($plan['plan_type'] ?? ''));

if ($ptype === 'installment' || $ptype === 'inst'
 || (($course_fee_lkr + $reg_fee_lkr + $cert_fee_usd) <= 0 && ($sumC + $sumR + $sumU) > 0)) {
  $course_fee_lkr = $sumC; $reg_fee_lkr = $sumR; $cert_fee_usd = max($cert_fee_usd, $sumU);
}

$discount_lkr = 0.0;
if (!empty($sfp)) {
  $discount_lkr += (float)($sfp['plan_discount_lkr']   ?? 0);
  $discount_lkr += (float)($sfp['manual_discount_lkr'] ?? 0);
  $discount_lkr += (float)($sfp['method_discount_lkr'] ?? 0);
} else if (tableExists($mysqli,'student_fee_plans')) {
  foreach (['discount_lkr','discount_amount_lkr','discount_amount'] as $c) {
    if (!colExists($mysqli,'student_fee_plans',$c)) continue;
    $st = $mysqli->prepare("SELECT `$c` AS d FROM student_fee_plans WHERE student_id=? ORDER BY id DESC LIMIT 1");
    $st->bind_param("i",$student_id); $st->execute();
    $r = stmt_fetch_one_assoc($st); $st->close();
    $discount_lkr = (float)($r['d'] ?? 0);
    break;
  }
}

/* payments history + paid totals */
$payments = [];
$already_paid_lkr = 0.0;
$paid_uka = 0.0;

if (tableExists($mysqli, 'payments')) {
  $pay_has_usd      = colExists($mysqli, 'payments', 'usd_amount');
  $pay_has_date     = colExists($mysqli, 'payments', 'date_paid');
  $pay_has_id       = colExists($mysqli, 'payments', 'id');
  $pay_has_student  = colExists($mysqli, 'payments', 'student_id');
  $pay_has_course   = colExists($mysqli, 'payments', 'course_id');
  $pay_has_plan     = colExists($mysqli, 'payments', 'plan_id');
  $has_sfp_tbl      = tableExists($mysqli, 'student_fee_plans');

  $whereParts = [];
  $types = '';
  $params = [];

  if ($pay_has_student) {
    $whereParts[] = "p.student_id = ?";
    $types .= 'i';
    $params[] = $student_id;
  }

  if ($resolved_course_id > 0) {
    if ($pay_has_course) {
      $whereParts[] = "p.course_id = ?";
      $types .= 'i';
      $params[] = $resolved_course_id;
    } elseif ($pay_has_plan && $has_sfp_tbl) {
      $whereParts[] = "sfp.course_id = ?";
      $types .= 'i';
      $params[] = $resolved_course_id;
    }
  }

  if ($whereParts) {
    $sql = "
      SELECT p.*
      FROM payments p
      " . (($pay_has_plan && $has_sfp_tbl) ? "LEFT JOIN student_fee_plans sfp ON sfp.id = p.plan_id" : "") . "
      WHERE " . implode(' AND ', $whereParts) . "
      ORDER BY " . ($pay_has_date ? "p.date_paid DESC, " : "") . ($pay_has_id ? "p.id DESC" : "1 DESC");

    $st = $mysqli->prepare($sql);
    if ($types !== '') $st->bind_param($types, ...$params);
    $st->execute();
    $payments = stmt_fetch_all_assoc($st);
    $st->close();
  }

  foreach ($payments as $pay) {
    $already_paid_lkr += numf($pay['amount'] ?? 0);
    if ($pay_has_usd) {
      $paid_uka += numf($pay['usd_amount'] ?? 0);
    }
  }
}

/* totals */
$sub_total_lkr     = $course_fee_lkr + $reg_fee_lkr;
$total_payable_lkr = max(0, $sub_total_lkr - max(0, $discount_lkr) + $late_charges + $extra_fee_lkr);
$outstanding_lkr = compute_outstanding_lkr($mysqli, $student_id, $resolved_course_id);
$has_any_payment_for_course = 0;

if (tableExists($mysqli, 'payments')) {
  $pay_has_student = colExists($mysqli, 'payments', 'student_id');
  $pay_has_course  = colExists($mysqli, 'payments', 'course_id');
  $pay_has_plan    = colExists($mysqli, 'payments', 'plan_id');
  $has_sfp_tbl     = tableExists($mysqli, 'student_fee_plans');

  $whereParts = [];
  $types = '';
  $params = [];

  if ($pay_has_student) {
    $whereParts[] = "p.student_id = ?";
    $types .= 'i';
    $params[] = $student_id;
  }

  if ($resolved_course_id > 0) {
    if ($pay_has_course) {
      $whereParts[] = "p.course_id = ?";
      $types .= 'i';
      $params[] = $resolved_course_id;
    } elseif ($pay_has_plan && $has_sfp_tbl) {
      $whereParts[] = "sfp.course_id = ?";
      $types .= 'i';
      $params[] = $resolved_course_id;
    }
  }

  if ($whereParts) {
    $sql = "
      SELECT COUNT(*) AS c
      FROM payments p
      " . (($pay_has_plan && $has_sfp_tbl) ? "LEFT JOIN student_fee_plans sfp ON sfp.id = p.plan_id" : "") . "
      WHERE " . implode(' AND ', $whereParts) . "
        AND COALESCE(p.amount,0) > 0
    ";

    $st = $mysqli->prepare($sql);
    if ($types !== '') $st->bind_param($types, ...$params);
    $st->execute();
    $row = stmt_fetch_one_assoc($st);
    $st->close();

    $has_any_payment_for_course = ((int)($row['c'] ?? 0) > 0) ? 1 : 0;
  }
}


/* ===== PAYMENT STATUS (UI-aligned) ===== */

/* use displayed totals as source of truth */
$calc_out_lkr = max(0.0, (float)$total_payable_lkr - (float)$already_paid_lkr);
$calc_out_usd = max(0.0, (float)$cert_fee_usd - (float)$paid_uka);

/* keep outstanding vars aligned with visible table */
$outstanding_lkr = $calc_out_lkr;
$out_lkr = $calc_out_lkr;
$out_usd = $calc_out_usd;

$has_any_payment = ((float)$already_paid_lkr > 0.009 || (float)$paid_uka > 0.009);

$has_overdue_month = 0;
$oldest_unpaid_due = null;
$is_overdue_3m     = 0;

if ($out_lkr > 0.009 || $out_usd > 0.009) {
  $has_overdue_month = compute_has_overdue_month($mysqli, $student_id, $resolved_course_id);
  $oldest_unpaid_due = compute_oldest_unpaid_due_date($mysqli, $student_id, $resolved_course_id);

  if ($oldest_unpaid_due) {
    $is_overdue_3m = (strtotime($oldest_unpaid_due) <= strtotime('-3 months')) ? 1 : 0;
  }
}

if ($lms_active === 0 || $lms_active === 2) {
  $payment_status = 'N/A';
} elseif ($out_lkr <= 0.009 && $out_usd <= 0.009) {
  $payment_status = 'Completed';
} elseif ($is_overdue_3m === 1) {
  $payment_status = 'Suspended';
} elseif ($has_overdue_month === 1) {
  $payment_status = 'Overdue';
} elseif ($has_any_payment) {
  $payment_status = 'Paid';
} else {
  $payment_status = 'Pending';
}
// verification / checklist
$ver = [];
if (tableExists($mysqli,'student_verifications')) {
  $st = $mysqli->prepare("SELECT * FROM student_verifications WHERE student_id=? LIMIT 1");
  $st->bind_param("i",$student_id); $st->execute();
  $ver = stmt_fetch_one_assoc($st); $st->close();
}
$is_verified = !empty($ver) && (int)($ver['verified'] ?? 0) === 1;

$chk_completed = 0; $chk_total = 6;
if (tableExists($mysqli,'student_checklist')) {
  $st = $mysqli->prepare("SELECT COUNT(*) AS c FROM student_checklist WHERE student_id=? AND is_done=1");
  $st->bind_param("i",$student_id); $st->execute();
  $tmp = stmt_fetch_one_assoc($st); $st->close();
  $chk_completed = (int)($tmp['c'] ?? 0);
}

// pretty fields
$reg_id_display = str_pad($student_id, 8, '0', STR_PAD_LEFT);
$created_at = $student['created_at'] ?? '';
$expiry = '';
if ($created_at) { $dt=new DateTime($created_at); $dt->modify('+1 year'); $expiry=$dt->format('Y-m-d'); }
$gender_badge = !empty($student['gender']) ? (' <span class="badge bg-dark-subtle text-dark">'.h($student['gender']).'</span>') : '';

// branch (robust)
$branch = '-';
if (!empty($student['branch_name'])) $branch = trim((string)$student['branch_name']);
elseif (!empty($student['branch']))  $branch = trim((string)$student['branch']);
elseif (!empty($student['branch_id']) && (int)$student['branch_id'] > 0 && tableExists($mysqli,'branches')) {
  $st = $mysqli->prepare("SELECT name FROM branches WHERE id=? LIMIT 1");
  $bid = (int)$student['branch_id'];
  $st->bind_param('i', $bid); $st->execute();
  $r = stmt_fetch_one_assoc($st); $st->close();
  if (!empty($r['name'])) $branch = (string)$r['name'];
} elseif (tableExists($mysqli,'enrollments') && tableExists($mysqli,'batches') && tableExists($mysqli,'branches') && colExists($mysqli,'batches','branch_id')) {
  $st = $mysqli->prepare("
    SELECT DISTINCT br.name
      FROM enrollments e
      JOIN batches b  ON b.id  = e.batch_id
      JOIN branches br ON br.id = b.branch_id
     WHERE e.student_id = ?
     ORDER BY br.name ASC");
  $st->bind_param('i', $student_id);
  $st->execute();
  $names = [];
  if (method_exists($st,'get_result')) {
    $rs = $st->get_result();
    while ($row = $rs->fetch_assoc()) { $nm = trim((string)($row['name'] ?? '')); if ($nm !== '') $names[] = $nm; }
  } else {
    $rows = stmt_fetch_all_assoc($st);
    foreach ($rows as $row) { $nm = trim((string)($row['name'] ?? '')); if ($nm !== '') $names[] = $nm; }
  }
  $st->close();
  if ($names) { $branch = $names[0]; if (count($names) > 1) { $branch .= ' (+' . (count($names)-1) . ')'; } }
}

/* === Course context for this view (only what we should show) === */
$context_course_ids = [];
$target_course_id = $course_id > 0 ? $course_id : $resolved_course_id;

if ($target_course_id > 0) {
  // If it's a bundle parent, use its children; else use itself
  if (tableExists($mysqli,'course_children')) {
    $st = $mysqli->prepare("SELECT child_id FROM course_children WHERE parent_id=?");
    $st->bind_param('i', $target_course_id);
    $st->execute();
    $rows = stmt_fetch_all_assoc($st);
    $st->close();
    foreach ($rows as $r) $context_course_ids[] = (int)$r['child_id'];
  }
  if (!$context_course_ids) $context_course_ids = [$target_course_id];
}

// reference display — only for selected course; bundle parent => children
$__refs = [];
if ($scope_child_ids) {
  // if a child has no row in student_numbers, fallback to its parent
  $parent_of = [];
  if (tableExists($mysqli,'course_children')) {
    $in = implode(',', array_map('intval',$scope_child_ids));
    if ($in) {
      $rs = $mysqli->query("SELECT child_id, parent_id FROM course_children WHERE child_id IN ($in)");
      if ($rs) { while ($r = $rs->fetch_assoc()) $parent_of[(int)$r['child_id']] = (int)$r['parent_id']; $rs->free(); }
    }
  }

  foreach ($scope_child_ids as $cid) {
    $refRow = $refs_by_course[$cid] ?? null;
    if (!$refRow && isset($parent_of[$cid])) $refRow = $refs_by_course[$parent_of[$cid]] ?? null;

    if ($refRow) {
      $ec1 = trim((string)($refRow['ec1'] ?? ''));
      $ec2 = trim((string)($refRow['ec2'] ?? ''));
      if ($ec1 !== '') $__refs[] = $ec1;
      if ($ec2 !== '') $__refs[] = $ec2;
    }
  }
}
$__refs = array_values(array_unique(array_filter($__refs)));

// final display value (fallback to legacy single fields only if nothing was found)
$ref_display = $__refs ? implode('/', $__refs) : ($reference_no ?: ($ver['student_ref_no'] ?? '-'));

// always include resolved course as a safety
if (!empty($resolved_course_id)) $enrolled_course_ids[] = (int)$resolved_course_id;
$enrolled_course_ids = array_values(array_unique(array_filter($enrolled_course_ids)));

// 2) map parents ↔ children (for bundle fallback to parent course_id rows in student_numbers)
$children_of = [];   // parent_id => [child_id...]
$parent_of   = [];   // child_id => parent_id
if ($enrolled_course_ids && tableExists($mysqli, 'course_children')) {
  // pull only mappings that involve enrolled parents
  $in = implode(',', array_map('intval', $enrolled_course_ids));
  $sql = "SELECT parent_id, child_id FROM course_children"
       . ($in ? " WHERE parent_id IN ($in)" : "");
  $rs = $mysqli->query($sql);
  if ($rs) {
    while ($row = $rs->fetch_assoc()) {
      $p = (int)$row['parent_id']; $c = (int)$row['child_id'];
      $children_of[$p][] = $c;
      $parent_of[$c] = $p;
    }
    $rs->free();
  }
}

// 3) expand courses to “all ids we should show ECs for”
$all_course_ids_for_refs = [];
foreach ($enrolled_course_ids as $cid0) {
  if (!empty($children_of[$cid0])) {
    // bundle → show ECs for each child
    $all_course_ids_for_refs = array_merge($all_course_ids_for_refs, $children_of[$cid0]);
  } else {
    // single course
    $all_course_ids_for_refs[] = $cid0;
  }
}
$all_course_ids_for_refs = array_values(array_unique($all_course_ids_for_refs));

// 4) build the EC list from student_numbers: prefer child row; else fall back to parent row
/* === Reference No (only selected course or its children if bundle) === */
$__refs = [];
foreach ($context_course_ids as $cid) {
  $r = $refs_by_course[$cid] ?? null;
  if ($r) {
    $ec1 = trim((string)($r['ec1'] ?? ''));
    $ec2 = trim((string)($r['ec2'] ?? ''));
    if ($ec1 !== '') $__refs[] = $ec1;
    if ($ec2 !== '') $__refs[] = $ec2;
  } else {
    // Optional fallback: if this child has no EC, try its parent’s EC once
    if (tableExists($mysqli,'course_children')) {
      $st = $mysqli->prepare("SELECT parent_id FROM course_children WHERE child_id=? LIMIT 1");
      $st->bind_param('i',$cid); $st->execute();
      $p = stmt_fetch_one_assoc($st); $st->close();
      if ($p) {
        $rp = $refs_by_course[(int)$p['parent_id']] ?? null;
        if ($rp) {
          $ec1 = trim((string)($rp['ec1'] ?? ''));
          $ec2 = trim((string)($rp['ec2'] ?? ''));
          if ($ec1 !== '') $__refs[] = $ec1;
          if ($ec2 !== '') $__refs[] = $ec2;
        }
      }
    }
  }
}
$__refs = array_values(array_unique(array_filter($__refs)));
if ($__refs) {
  usort($__refs, function($a,$b){
    $na = (int)preg_replace('/\D+/', '', $a); $nb = (int)preg_replace('/\D+/', '', $b);
    return ($na <=> $nb) ?: strcmp($a,$b);
  });
  $ref_display = implode('/', $__refs);
} else {
  // only if nothing was found for the course context
  $ref_display = $reference_no ?: ($ver['student_ref_no'] ?? '-');
}


// Add Payment modal data-attrs precompute (allocation-safe)
$paid_course=0.0; $paid_reg_lkr=0.0; $paid_uka=0.0;
$has_fee_types_col = tableExists($mysqli,'payments') && (colExists($mysqli,'payments','fee_type') || colExists($mysqli,'payments','items_json')) ? 1 : 0;
if (tableExists($mysqli,'payments')) {
  $cols = ['id','amount'];
  $has_pay_usd   = colExists($mysqli,'payments','usd_amount');
  $has_pay_ftype = colExists($mysqli,'payments','fee_type');
  $has_pay_items = colExists($mysqli,'payments','items_json');
  $has_pay_curr  = colExists($mysqli,'payments','currency');
  if ($has_pay_usd)   $cols[] = 'usd_amount';
  if ($has_pay_ftype) $cols[] = 'fee_type';
  if ($has_pay_items) $cols[] = 'items_json';
  if ($has_pay_curr)  $cols[] = 'currency';
  $sql = "SELECT ".implode(',', $cols)." FROM payments WHERE student_id=? ORDER BY date_paid ASC, id ASC";
  $st = $mysqli->prepare($sql); $st->bind_param('i',$student_id); $st->execute();
  $rows = stmt_fetch_all_assoc($st); $st->close();

  $course_due_after_discount = max(0.0, (float)$course_fee_lkr - max(0.0,(float)$discount_lkr));
  $rem_course = $course_due_after_discount; $rem_reg=(float)$reg_fee_lkr;
  foreach ($rows as $p) {
    $amtL = (float)($p['amount'] ?? 0); $amtU = (float)($p['usd_amount'] ?? 0);
    $ft   = strtolower(trim((string)($p['fee_type'] ?? '')));
    $cur  = strtoupper(trim((string)($p['currency'] ?? '')));
    if ($amtU > 0 || $cur === 'USD') $paid_uka += ($amtU > 0) ? $amtU : 0.0;

    $j = json_decode((string)($p['items_json'] ?? ''), true);
    if (is_array($j) && isset($j['items']) && is_array($j['items'])) {
      foreach ($j['items'] as $it) {
        $type = strtolower(trim((string)($it['type'] ?? '')));
        $ccy  = strtoupper(trim((string)($it['currency'] ?? 'LKR')));
        $a    = (float)($it['amount'] ?? 0);
        if ($ccy === 'USD' && $type === 'uk awards fee') { $paid_uka     += $a; }
        if ($ccy === 'LKR' && $type === 'course fee')    { $paid_course  += $a; }
        if ($ccy === 'LKR' && $type === 'registration fee'){ $paid_reg_lkr += $a; }
      }
      continue;
    }
    if ($ft === 'course fee' || $ft === 'course_fee') { $paid_course += $amtL; continue; }
    if ($ft === 'registration fee' || $ft === 'registration_fee' || $ft === 'reg_fee') { $paid_reg_lkr += $amtL; continue; }
    if ($ft === 'uk awards fee' || $ft === 'uk_awards') { if ($amtU > 0) $paid_uka += $amtU; continue; }
    // fallback allocation
    if ($amtL > 0) {
      $take_course = min($amtL, max(0.0, $rem_course - $paid_course));
      if ($take_course > 0) { $paid_course += $take_course; $amtL -= $take_course; }
      if ($amtL > 0) {
        $take_reg = min($amtL, max(0.0, $rem_reg - $paid_reg_lkr));
        if ($take_reg > 0) { $paid_reg_lkr += $take_reg; $amtL -= $take_reg; }
      }
    }
  }
}
$__course_total   = number_format((float)$course_fee_lkr, 2, '.', '');
$__course_paid    = number_format((float)$paid_course,     2, '.', '');
$__uka_total      = number_format((float)$cert_fee_usd,    2, '.', '');
$__uka_paid       = number_format((float)$paid_uka,        2, '.', '');
$__has_fee_types  = (string)$has_fee_types_col;
$__out_lkr        = number_format((float)$outstanding_lkr, 2, '.', '');

$SID = (int)$student_id;
$customModalId = 'customPlanModal-' . $SID;

/* ===== Balance Summary: use allocation-safe paid totals + discount-aware balances ===== */

$rem_course = max(0.0, (float)$course_fee_lkr - max(0.0, (float)$discount_lkr));
$rem_reg    = max(0.0, (float)$reg_fee_lkr);
$rem_uka    = max(0.0, (float)$cert_fee_usd);

/* keep earlier allocation-safe values if already computed */
$paid_course  = isset($paid_course)  ? (float)$paid_course  : 0.0;
$paid_reg_lkr = isset($paid_reg_lkr) ? (float)$paid_reg_lkr : 0.0;
$paid_uka     = isset($paid_uka)     ? (float)$paid_uka     : 0.0;

/* fallback: if fee-type allocation was not computed earlier, derive from payments */
if (($paid_course + $paid_reg_lkr + $paid_uka) <= 0.00001 && !empty($payments)) {
  foreach ($payments as $pay) {
    $ft   = strtolower(trim((string)($pay['fee_type'] ?? '')));
    $amtL = numf($pay['amount'] ?? 0);
    $amtU = numf($pay['usd_amount'] ?? 0);

    if ($ft === 'mixed') {
      $j = json_decode((string)($pay['items_json'] ?? ''), true);
      $items = is_array($j['items'] ?? null) ? $j['items'] : [];
      foreach ($items as $it) {
        $type = strtolower(trim((string)($it['type'] ?? '')));
        $ccy  = strtoupper(trim((string)($it['currency'] ?? 'LKR')));
        $a    = numf($it['amount'] ?? 0);

        if ($ccy === 'USD' && $type === 'uk awards fee') { $paid_uka += $a; continue; }
        if ($ccy === 'LKR' && $type === 'course fee')    { $paid_course += $a; continue; }
        if ($ccy === 'LKR' && $type === 'registration fee') { $paid_reg_lkr += $a; continue; }
      }
      continue;
    }

    if ($ft === 'course fee' || $ft === 'course_fee') {
      $paid_course += $amtL; continue;
    }
    if ($ft === 'registration fee' || $ft === 'registration_fee' || $ft === 'reg_fee') {
      $paid_reg_lkr += $amtL; continue;
    }
    if ($ft === 'uk awards fee' || $ft === 'uk_awards') {
      $paid_uka += $amtU; continue;
    }

    /* fallback allocate LKR into discounted course first, then reg */
    if ($amtL > 0) {
      $take_course = min($amtL, max(0.0, $rem_course - $paid_course));
      if ($take_course > 0) { $paid_course += $take_course; $amtL -= $take_course; }

      if ($amtL > 0) {
        $take_reg = min($amtL, max(0.0, $rem_reg - $paid_reg_lkr));
        if ($take_reg > 0) { $paid_reg_lkr += $take_reg; $amtL -= $take_reg; }
      }
    }
  }
}

$course_balance_lkr   = max(0.0, $rem_course - $paid_course);
$reg_balance_lkr      = max(0.0, $rem_reg - $paid_reg_lkr);
$uka_balance_usd      = max(0.0, $rem_uka - $paid_uka);

$balance_subtotal_lkr = $course_balance_lkr + $reg_balance_lkr;
$balance_subtotal_usd = $uka_balance_usd;

$__course_balance = number_format((float)$course_balance_lkr, 2, '.', '');
$__reg_balance    = number_format((float)$reg_balance_lkr, 2, '.', '');
$__uka_balance    = number_format((float)$uka_balance_usd, 2, '.', '');

?>
<?php if (!$is_embed): ?>



<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Student Overview</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- Only include libs in full page mode -->
  <link rel="stylesheet" href="/assets/css/bootstrap.min.css">
  <link rel="stylesheet" href="/assets/css/bootstrap-icons.css">
<?php endif; ?>
  <style>
    /* Compact layout scoped to #actionModal */
    #actionModal .modal-body, #actionModal .modal-body *{font-size:.85rem}
    #actionModal .container.mt-3{margin-top:0!important}
    #actionModal .nav-tabs{margin-top:.25rem;margin-bottom:.35rem}
    #actionModal .card{margin-bottom:.35rem}
    #actionModal .card.shadow-sm.mb-3{margin-bottom:.35rem!important}
    #actionModal .card-body{padding:.5rem .6rem}
    #actionModal .card-header, #actionModal .ps-head{padding:.4rem .6rem}
    #actionModal h4{font-size:1rem;margin:0}
    #actionModal .table>:not(caption)>*>*{padding:.35rem .45rem}
    #actionModal .kv-row{display:flex;gap:10px;align-items:center;margin:.2rem 0}
    #actionModal .kv-row .k{min-width:150px;color:#6c757d}
    #actionModal .kv-row .v{font-weight:500}
    #actionModal .kv-group{background:#fff;border:1px solid #e9ecef;border-radius:.45rem;padding:.75rem}
    #actionModal .kv-title{font-weight:600;margin-bottom:.35rem}
    #actionModal .overview-banner{background:#fff3cd;border:1px solid #ffe69c;border-radius:.35rem;padding:8px 12px}
    #actionModal .letter-card{display:block;border:1px solid #e9ecef;border-radius:.45rem;padding:10px 12px;text-decoration:none;background:#fff;color:#0d6efd;min-height:90px}
    #actionModal .letter-card .lc-head{font-weight:700;font-size:.9rem;text-transform:uppercase}
    #actionModal .letter-card .lc-points{margin:.35rem 0 0;padding-left:0;list-style:none}
    #actionModal .letter-card .lc-points li{font-size:.8rem;margin:.1rem 0}
    #actionModal .ps-card{background:#fff;border:1px solid #e9ecef;border-radius:.45rem}
    #actionModal .ps-table th,#actionModal .ps-table td{vertical-align:middle;padding:.35rem .45rem}
    #actionModal .big-stat{font-size:1.4rem;font-weight:700}
    #actionModal .big-stat-wrap{display:flex;justify-content:center;align-items:center;height:100%;padding:12px 0}
    #actionModal .bundle-chip{border-radius:999px;padding:.2rem .6rem}
    #actionModal .modal-header{ padding:.50rem .75rem !important; }
    #actionModal .modal-header .modal-title{ font-size:1rem !important; line-height:1.1 !important; margin:0 !important; font-weight:700; }
    #actionModal .btn-close{ transform:scale(.9); }
    #actionModal .modal-body{ padding-top:.5rem !important; }
    #actionModal .modal-header + .modal-body > *:first-child{ margin-top:0 !important; }
    #actionModal .container.mt-3{ margin-top:.2rem !important; }
    #actionModal .card.shadow-sm.mb-3{ margin-bottom:.35rem !important; }
    #actionModal .card.shadow-sm.mb-3 .card-body{ padding:.45rem .6rem !important; }
    #actionModal .card.shadow-sm.mb-3 h4{ font-size:1rem !important; margin:0 !important; }
    #actionModal .nav-tabs{ margin:.25rem 0 .35rem !important; }
    #actionModal .table>:not(caption)>*>*{ padding:.35rem .45rem !important; }
    #customPlanModal .modal-dialog { margin-top:.25rem; }
    /* left-aligned everything inside modal */
    #actionModal .modal-body, #actionModal .modal-body .card, #actionModal .modal-body .card-header,
    #actionModal .modal-body .card-body, #actionModal .modal-body .tab-pane, #actionModal .modal-body .row,
    #actionModal .modal-body .col, #actionModal .modal-body .kv-group, #actionModal .modal-body .kv-row .k,
    #actionModal .modal-body .kv-row .v, #actionModal .modal-body table, #actionModal .modal-body table td,
    #actionModal .modal-body table th, #actionModal .modal-body .form-check, #actionModal .modal-body .form-check-label {
      text-align:left !important;
    }
.payment-history-card{
  border: 1px solid #dfe3e8;
  border-radius: 0;
  overflow: hidden;
  background: #fff;
}

.payment-history-head{
  background: #f8f9fb;
  border-bottom: 1px solid #dfe3e8;
  padding: 12px 16px;
}

.payment-history-head h6{
  color: #2b4ea1;
  font-size: 20px;
}

.payment-history-table thead th{
  background: #f3f4f6;
  color: #111827;
  font-weight: 700;
  font-size: 14px;
  padding: 14px 12px;
  vertical-align: middle;
  white-space: nowrap;
  border-bottom: 1px solid #dfe3e8;
}

.payment-history-table tbody td{
  padding: 16px 12px;
  font-size: 14px;
  vertical-align: middle;
  border-top: 1px solid #edf1f5;
}

.payment-history-table tbody tr:hover{
  background: #fafcff;
}

.ph-badge{
  display: inline-block;
  min-width: 76px;
  padding: 4px 14px;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  text-align: center;
  line-height: 1.4;
}

.ph-badge.paid{
  background: #1f7a34;
}

.ph-date-main{
  font-weight: 600;
  color: #111827;
}

.ph-date-sub{
  font-size: 12px;
  color: #6b7280;
  margin-top: 2px;
}

.ph-details-btn{
  color: #2a4dbb;
  font-weight: 500;
}

.ph-details-btn:hover{
  color: #1d3f9b;
  text-decoration: underline !important;
}

.ph-print-btn{
  width: 32px;
  height: 32px;
  border-radius: 0;
  border: 1px solid #6b7280;
  background: #6b7280;
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.ph-print-btn:hover{
  background: #4b5563;
  border-color: #4b5563;
  color: #fff;
}
.verify-modal{
  border:0;
  border-radius:22px;
  overflow:hidden;
  box-shadow:0 20px 60px rgba(15,23,42,.18);
  background:linear-gradient(180deg,#ffffff 0%,#f8fbff 100%);
}

.verify-kicker{
  display:inline-block;
  font-size:.72rem;
  font-weight:800;
  letter-spacing:.08em;
  color:#0d6efd;
  background:#eaf2ff;
  border:1px solid #d7e7ff;
  border-radius:999px;
  padding:4px 10px;
  margin-bottom:8px;
}

.verify-subtitle{
  color:#6b7280;
  font-size:.92rem;
}

.verify-form .form-label{
  font-weight:700;
  color:#1f2937;
  margin-bottom:8px;
}

.verify-card{
  background:#fff;
  border:1px solid #e8eef7;
  border-radius:18px;
  padding:18px;
  box-shadow:0 10px 30px rgba(15,23,42,.04);
}

.verify-card-title{
  font-size:.9rem;
  font-weight:800;
  color:#0f172a;
  margin-bottom:14px;
}

.verify-input-group{
  border-radius:14px;
  overflow:hidden;
  box-shadow:none;
}

.verify-input-group .input-group-text{
  background:#f8fafc;
  border:1px solid #dbe4f0;
  border-right:0;
  color:#64748b;
  min-width:46px;
  justify-content:center;
}

.verify-input-group .form-control{
  border:1px solid #dbe4f0;
  border-left:0;
  min-height:48px;
  font-size:.95rem;
  box-shadow:none;
}

.verify-input-group .form-control:focus{
  box-shadow:none;
}

.verify-note{
  display:flex;
  gap:12px;
  align-items:flex-start;
  background:linear-gradient(135deg,#eff8ff 0%,#f8fbff 100%);
  border:1px solid #d9ebff;
  color:#0f172a;
  padding:14px 16px;
  border-radius:16px;
  font-size:.92rem;
}

.verify-note-icon{
  width:38px;
  height:38px;
  flex:0 0 38px;
  border-radius:12px;
  display:flex;
  align-items:center;
  justify-content:center;
  background:#dbeafe;
  color:#0d6efd;
  font-size:1rem;
}

.verify-btn-cancel{
  min-width:100px;
  border-radius:12px;
  padding:10px 18px;
  font-weight:700;
}

.verify-btn-save{
  min-width:150px;
  border-radius:12px;
  padding:10px 18px;
  font-weight:800;
  color:#fff;
  border:0;
  background:linear-gradient(135deg,#16a34a 0%,#059669 100%);
  box-shadow:0 10px 20px rgba(5,150,105,.22);
}

.verify-btn-save:hover{
  color:#fff;
  transform:translateY(-1px);
}

.verify-alert{
  border-radius:14px;
  padding:12px 14px;
  font-size:.92rem;
  border:1px solid transparent;
}

.verify-alert-success{
  background:#ecfdf3;
  border-color:#bbf7d0;
  color:#166534;
}

.verify-alert-danger{
  background:#fef2f2;
  border-color:#fecaca;
  color:#991b1b;
}


/* =========================================================
   MATCHING VERIFICATION MODAL + OTP MODAL
   ========================================================= */

/* ---------- shared modal shell ---------- */
#studentVerifyModal .modal-dialog{
  max-width: 920px;
}

#otpModal .modal-dialog{
  max-width: 460px;
}

.sv-modal,
.otp3-modal{
  border: 0;
  border-radius: 24px;
  overflow: hidden;
  background: #ffffff;
  box-shadow: 0 24px 70px rgba(15,23,42,.18);
}

.sv-topbar,
.otp3-topbar{
  height: 5px;
  background: linear-gradient(90deg, #2563eb 0%, #38bdf8 100%);
}

.sv-header,
.otp3-header{
  padding: 16px 20px 10px;
}

.sv-badge,
.otp3-badge{
  display: inline-block;
  background: #eef4ff;
  color: #2563eb;
  border: 1px solid #dbe7ff;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .08em;
  border-radius: 999px;
  padding: 5px 10px;
  margin-bottom: 8px;
}

.sv-title,
.otp3-title{
  font-size: 1.18rem;
  font-weight: 800;
  color: #0f172a;
  margin: 0 0 4px;
}

.sv-subtitle,
.otp3-subtitle{
  font-size: .9rem;
  color: #64748b;
  line-height: 1.35;
}

.sv-close{
  opacity: .75;
}

/* ---------- shared buttons ---------- */
.sv-btn-light,
.otp3-btn-light{
  min-width: 96px;
  height: 40px;
  border-radius: 12px;
  font-weight: 700;
  border: 1px solid #dbe2ea;
  background: #f8fafc;
  color: #334155;
}

.sv-btn-light:hover,
.otp3-btn-light:hover{
  background: #f1f5f9;
  color: #1e293b;
}

.sv-btn-primary,
.otp3-btn-primary{
  min-width: 122px;
  height: 40px;
  border-radius: 12px;
  font-weight: 800;
  border: 0;
  color: #fff;
  background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
  box-shadow: 0 10px 22px rgba(37,99,235,.18);
}

.sv-btn-primary:hover,
.otp3-btn-primary:hover{
  color: #fff;
}

/* ---------- shared alerts ---------- */
.verify-alert,
.otp-alert{
  border-radius: 12px;
  padding: 11px 13px;
  font-size: .88rem;
}

.verify-alert-success,
.otp-alert-success{
  background: #ecfdf3;
  color: #166534;
  border: 1px solid #bbf7d0;
}

.verify-alert-danger,
.otp-alert-danger{
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fecaca;
}

/* =========================================================
   VERIFICATION MODAL
   ========================================================= */
.sv-body{
  padding: 8px 20px 8px;
}

.sv-section-card{
  border: 1px solid #e6edf7;
  border-radius: 20px;
  background: linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
  padding: 16px;
}

.sv-section-head{
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 10px;
}

.sv-section-icon{
  width: 40px;
  height: 40px;
  border-radius: 14px;
  background: linear-gradient(180deg, #eef4ff 0%, #dbeafe 100%);
  color: #2563eb;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  flex: 0 0 40px;
}

.sv-section-title{
  font-weight: 800;
  color: #0f172a;
  font-size: .98rem;
}

.sv-section-sub{
  color: #64748b;
  font-size: .86rem;
  margin-top: 2px;
}

.sv-label{
  display: block;
  font-size: .86rem;
  font-weight: 700;
  color: #1e293b;
  margin-bottom: 7px;
}

.sv-input-wrap{
  position: relative;
}

.sv-input-icon{
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  color: #64748b;
  z-index: 2;
}

.sv-input{
  height: 48px;
  border-radius: 14px;
  border: 1px solid #d8e1ee;
  padding-left: 42px;
  font-size: .94rem;
  color: #1f2937;
  box-shadow: none !important;
}

.sv-input[readonly]{
  background: #f8fafc;
}

.sv-input:focus{
  border-color: #93c5fd;
  box-shadow: 0 0 0 .16rem rgba(37,99,235,.10) !important;
}

.sv-note-card{
  display: flex;
  gap: 14px;
  align-items: flex-start;
  border: 1px solid #dbeafe;
  background: linear-gradient(180deg, #f8fbff 0%, #f1f7ff 100%);
  border-radius: 18px;
  padding: 15px;
}

.sv-note-icon{
  width: 40px;
  height: 40px;
  border-radius: 14px;
  background: linear-gradient(180deg, #eef4ff 0%, #dbeafe 100%);
  color: #2563eb;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  flex: 0 0 40px;
}

.sv-note-title{
  font-weight: 800;
  color: #0f172a;
  margin-bottom: 3px;
  font-size: .95rem;
}

.sv-note-text{
  color: #475569;
  font-size: .9rem;
  line-height: 1.4;
}

.sv-footer{
  padding: 12px 20px 18px;
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

/* =========================================================
   OTP MODAL - CLEAN MODERN UI
   ========================================================= */
#otpModal .modal-dialog{
  max-width: 430px;
}

#otpModal .modal-content{
  border: 0;
  border-radius: 26px;
  overflow: hidden;
  background: #ffffff;
  box-shadow: 0 28px 70px rgba(15, 23, 42, 0.20);
}

#otpModal .modal-header{
  border-bottom: 0;
  padding: 18px 20px 10px;
  align-items: flex-start;
}

#otpModal .btn-close{
  box-shadow: none !important;
  opacity: .7;
}

#otpModal .btn-close:hover{
  opacity: 1;
}

.otp3-body{
  padding: 0 20px 14px;
}

.otp3-top{
  text-align: center;
  margin-bottom: 14px;
}

.otp3-icon-wrap{
  display: flex;
  justify-content: center;
  margin-bottom: 14px;
}

.otp3-icon{
  width: 72px;
  height: 72px;
  border-radius: 22px;
  background: linear-gradient(180deg, #eff6ff 0%, #dbeafe 100%);
  color: #2563eb;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.8);
}

.otp3-icon i{
  font-size: 1.9rem;
  line-height: 1;
}

.otp3-badge{
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 999px;
  background: #eff6ff;
  border: 1px solid #dbeafe;
  color: #1d4ed8;
  font-size: .74rem;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  margin-bottom: 10px;
}

.otp3-title{
  margin: 0;
  color: #0f172a;
  font-size: 1.24rem;
  font-weight: 800;
  line-height: 1.2;
}

.otp3-subtitle{
  margin: 8px auto 0;
  max-width: 310px;
  color: #64748b;
  font-size: .92rem;
  line-height: 1.5;
}

.otp3-card{
  border: 1px solid #e5edf8;
  border-radius: 22px;
  background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
  padding: 16px;
}

.otp3-label{
  display: block;
  margin-bottom: 8px;
  color: #1e293b;
  font-size: .88rem;
  font-weight: 700;
}

.otp3-input{
  height: 56px;
  border-radius: 16px;
  border: 1px solid #d7e2f0;
  text-align: center;
  font-size: 1.45rem;
  font-weight: 800;
  letter-spacing: .34em;
  color: #0f172a;
  box-shadow: none !important;
  padding-left: 18px;
  padding-right: 12px;
  background: #fff;
}

.otp3-input::placeholder{
  color: #94a3b8;
  letter-spacing: .28em;
  font-size: 1.02rem;
}

.otp3-input:focus{
  border-color: #93c5fd;
  box-shadow: 0 0 0 .18rem rgba(37,99,235,.14) !important;
}

.otp3-help{
  text-align: center;
  color: #64748b;
  font-size: .84rem;
  margin-top: 11px;
  line-height: 1.45;
}

.otp3-devhint{
  margin-top: 12px;
  padding: 12px 14px;
  border-radius: 15px;
  background: #fff7ed;
  border: 1px solid #fdba74;
  color: #9a3412;
  font-size: .88rem;
  font-weight: 700;
  text-align: center;
  word-break: break-word;
}

.otp3-footer{
  border-top: 0 !important;
  padding: 0 20px 20px;
  display: flex;
  gap: 10px;
}

.otp3-footer .btn{
  height: 48px;
  border-radius: 14px;
  font-weight: 700;
  font-size: .94rem;
}

.otp3-btn-light{
  flex: 1 1 42%;
  background: #f8fafc;
  border: 1px solid #dbe3ee;
  color: #334155;
}

.otp3-btn-light:hover{
  background: #f1f5f9;
  color: #0f172a;
}

.otp3-btn-primary{
  flex: 1 1 58%;
  border: 0;
  color: #fff;
  background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
  box-shadow: 0 14px 28px rgba(37,99,235,.24);
}

.otp3-btn-primary:hover{
  color: #fff;
  background: linear-gradient(135deg, #1d4ed8 0%, #1e40af 100%);
}

.otp-alert{
  border-radius: 14px;
  padding: 11px 13px;
  font-size: .88rem;
  font-weight: 600;
}

.otp-alert-danger{
  background: #fef2f2;
  border: 1px solid #fecaca;
  color: #b91c1c;
}

.otp-alert-success{
  background: #ecfdf5;
  border: 1px solid #bbf7d0;
  color: #047857;
}

@media (max-width: 575.98px){
  #otpModal .modal-dialog{
    max-width: calc(100vw - 20px);
    margin: 10px auto;
  }

  #otpModal .modal-header{
    padding: 16px 16px 8px;
  }

  .otp3-body{
    padding: 0 16px 12px;
  }

  .otp3-card{
    padding: 14px;
    border-radius: 18px;
  }

  .otp3-icon{
    width: 64px;
    height: 64px;
    border-radius: 20px;
  }

  .otp3-input{
    height: 52px;
    font-size: 1.22rem;
    letter-spacing: .26em;
  }

  .otp3-footer{
    padding: 0 16px 16px;
    flex-direction: column;
  }

  .otp3-footer .btn{
    width: 100%;
  }
}
</style>
<?php if (!$is_embed): ?>
</head>
<body>
<?php endif; ?>
<!-- keep everything from <div class="container mt-3"> ... all your modals + inline scripts ... -->
<div class="container mt-3"><!-- mt reduced via CSS above -->

  <!-- Header -->
  <div class="card shadow-sm mb-3">
    <div class="card-body d-flex align-items-center">
      <div>
        <h4 class="mb-0"><?= h($student['full_name'] ?? 'Unknown Student') ?></h4>
        <small class="text-muted">Reg No: <?= h($center_reg_no ?: '-') ?></small>
      </div>
    </div>
  </div>

  <!-- Tabs -->
  <ul class="nav nav-tabs" id="studentTabs" role="tablist">
    <li class="nav-item"><a class="nav-link active" data-bs-toggle="tab" href="#overview">Overview</a></li>
    <li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#course">Course Info</a></li>
    <li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#payments">Payments</a></li>
    <li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#other">Other</a></li>
  </ul>

  <div class="tab-content mt-3">

    <!-- OVERVIEW -->
<div class="tab-pane fade show active" id="overview">
  <?php if (!$is_verified): ?>
  <div class="overview-banner mb-3">
    <div class="fw-semibold mb-1">Incomplete Registration</div>
    <div class="ovr-hint mb-2">The registration process has been interrupted because of the following reason(s).</div>
    <div class="d-flex align-items-center gap-2">
      <i class="bi bi-exclamation-triangle-fill text-warning"></i>
      <span>Unverified Registration. Name verification has to be done</span>
      <a href="#" id="goVerify" class="ms-2 fw-semibold">Verify</a>
    </div>
  </div>
  <?php endif; ?>

  <div class="row g-3">
    <!-- Left -->
    <div class="col-lg-6">
      <div class="kv-group">
        <div class="kv-title"><i class="bi bi-info-circle me-1"></i>Details</div>

        <div class="kv-row">
          <div class="k">Registration Status</div>
          <div class="v">
            <?= $is_verified
              ? '<span class="badge bg-success">Verified</span>'
              : '<span class="badge bg-warning text-dark">Pending Verification</span>' ?>
          </div>
        </div>

        <div class="kv-row"><div class="k">Student ID</div><div class="v"><?= h($center_reg_no ?: '-') ?></div></div>

        <div class="kv-row"><div class="k">Student Name</div><div class="v"><?= h($student['full_name'] ?? '-') ?><?= $gender_badge ?></div></div>

        <div class="kv-row">
          <div class="k">Course</div>
          <div class="v">
            <?= h($course['course_name'] ?? $course['name'] ?? '-') ?><br>
            <small class="text-muted"><?= h($course['description'] ?? '') ?></small>
          </div>
        </div>

        <div class="kv-row"><div class="k">Branch Enrolled</div><div class="v"><?= h($branch ?: '-') ?></div></div>

        <!-- Batch(es) — show ONLY the batch_code -->
        <div class="kv-row">
          <div class="k">Batch(es)</div>
            <div class="v">
    <?php
      // numeric PK from studentss table
      $studentDbId     = (int)($student['id'] ?? 0);
      $studentBatches  = ec_get_student_batches($mysqli, $studentDbId);
    ?>

    <?php if (!empty($studentBatches)): ?>
      <?php foreach ($studentBatches as $b): ?>
        <?php $code = trim((string)($b['batch_code'] ?? '')); ?>
        <div>
          <?= $code !== '' ? h($code) : '—' ?>
          <?php if (!empty($b['status']) && strtolower((string)$b['status']) === 'active'): ?>
            <i class="bi bi-check-circle-fill text-success ms-1"></i>
          <?php endif; ?>
        </div>
      <?php endforeach; ?>
    <?php else: ?>
      —
    <?php endif; ?>
  </div>

        </div>
        <!-- /Batch(es) -->
      </div>
    </div>

        <!-- Right -->
        <div class="col-lg-6">
          <div class="kv-group">
            <div class="kv-title"><i class="bi bi-clipboard-data me-1"></i>Registration</div>
            <div class="kv-row">
  <div class="k">Payment Status</div>
  <div class="v">
<span class="badge <?= h(match($payment_status){
  'Completed' => 'bg-success',
  'Paid'      => 'bg-success',
  'Pending'   => 'bg-secondary',
  'Overdue'   => 'bg-danger',
  'Suspended' => 'bg-warning text-dark',
  'N/A'       => 'bg-secondary',
  default     => 'bg-secondary',
}) ?>"><?= h($payment_status) ?></span>
  </div>
</div>
            <div class="kv-row"><div class="k">Registration ID</div><div class="v"><?= h($reg_id_display) ?></div></div>
            <div class="kv-row"><div class="k">Reference No</div><div class="v"><?= h($ref_display) ?></div></div>
            <div class="kv-row"><div class="k">Date Registered</div><div class="v"><?= h($created_at ?: '-') ?></div></div>
            <div class="kv-row"><div class="k">Date Expiry</div><div class="v"><?= h($expiry ?: '-') ?></div></div>
            <div class="kv-row"><div class="k">Checklist</div><div class="v"><?= (int)$chk_completed ?> / <?= (int)$chk_total ?> Completed</div></div>
          </div>
        </div>
      </div>

      <!-- Payment Summary + Accumulated Dues -->
      <div class="row g-3 mt-1">
        <div class="col-lg-8">
          <div class="ps-card">
            <div class="ps-head"><h6 class="fw-bold m-0"><i class="bi bi-table me-1"></i>Payment Summary</h6></div>
            <div class="ps-body">
              <table class="table table-bordered m-0 ps-table text-center">
                <thead class="table-light">
                  <tr>
                    <th style="width:80px"></th>
                    <th>Total Payable</th>
                    <th>Already Paid Total</th>
                    <th>Total Outstanding</th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <th>LKR</th>
                    <td><?= nf($total_payable_lkr) ?></td>
                    <td><?= nf($already_paid_lkr) ?></td>
                    <td><?= nf($outstanding_lkr) ?></td>
                  </tr>
                  <tr>
                    <th>USD</th>
                    <td><?= nf($cert_fee_usd) ?></td>
                    <td><?= nf($paid_uka) ?></td>
                    <td><?= nf(max(0, $cert_fee_usd - $paid_uka)) ?></td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
        </div>

        <div class="col-lg-4">
          <div class="ps-card h-100">
            <div class="ps-head"><h6 class="fw-bold m-0"><i class="bi bi-graph-up-arrow me-1"></i>Accumulated Dues</h6></div>
            <div class="big-stat-wrap">
              <div class="text-center">
                <div class="big-stat text-danger"><?= nf($outstanding_lkr) ?></div>
                <div class="ovr-hint">LKR</div>
                <div class="mt-2 text-muted"><?= nf(max(0, $cert_fee_usd - $paid_uka)) ?> USD</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div><!-- /overview -->

<!-- COURSE INFO -->
<div class="tab-pane fade" id="course">

  <!-- Course Details -->
  <div class="card mb-3">
    <div class="card-header"><h6 class="fw-bold m-0">Course Details</h6></div>
    <div class="card-body">
      <table class="table table-bordered mb-0">
        <tr><th style="width:220px">Name</th><td><?= h($course['course_name'] ?? $course['name'] ?? '-') ?></td></tr>
        <tr><th>Duration</th><td><?= h($course['duration'] ?? '-') ?><?= isset($course['duration']) ? ' months' : '' ?></td></tr>
        <tr><th>Description</th><td><?= h($course['description'] ?? $course['course_description'] ?? '-') ?></td></tr>
      </table>
    </div>
  </div>

<!-- Bundle chips -->
<?php if (!empty($bundle_children)): ?>
  <div class="mb-3">
    <?php foreach ($bundle_children as $i => $bc):
      $cid = (int)$bc['id'];
      $courseCode = trim((string)($bc['code'] ?? $bc['label'] ?? 'Course'));

      $ecLabel = '';

      // 1) child course එකට direct reference තියෙනවා නම් ඒක ගන්න
      $r = $refs_by_course[$cid] ?? null;
      if ($r) {
        $ec1 = trim((string)($r['ec1'] ?? ''));
        $ec2 = trim((string)($r['ec2'] ?? ''));

        // Direct child row එකේ primary ref එක විතරක්
        $ecLabel = $ec1 !== '' ? $ec1 : $ec2;
      }

      // 2) child row නැත්නම් parent bundle row එකෙන් child order අනුව ගන්න
      if ($ecLabel === '' && tableExists($mysqli, 'course_children')) {
        $stp = $mysqli->prepare("
          SELECT parent_id, child_id
          FROM course_children
          WHERE parent_id = (
            SELECT parent_id FROM course_children WHERE child_id=? LIMIT 1
          )
          ORDER BY sort_order ASC, child_id ASC
        ");
        $stp->bind_param('i', $cid);
        $stp->execute();
        $siblings = stmt_fetch_all_assoc($stp);
        $stp->close();

        $parentId = 0;
        $childIndex = 0;

        foreach ($siblings as $idx => $sr) {
          if ((int)$sr['child_id'] === $cid) {
            $parentId = (int)$sr['parent_id'];
            $childIndex = $idx; // 0 = first child, 1 = second child
            break;
          }
        }

        if ($parentId > 0 && isset($refs_by_course[$parentId])) {
          $pr = $refs_by_course[$parentId];

          $pEc1 = trim((string)($pr['ec1'] ?? ''));
          $pEc2 = trim((string)($pr['ec2'] ?? ''));

          // first course => reference_no, second course => reference_no2
          if ($childIndex === 0) {
            $ecLabel = $pEc1 !== '' ? $pEc1 : $pEc2;
          } elseif ($childIndex === 1) {
            $ecLabel = $pEc2 !== '' ? $pEc2 : $pEc1;
          }
        }
      }

      // 3) final fallback
      if ($ecLabel === '') {
        $ecLabel = trim((string)($reference_no ?? ''));
      }

      $chipText = $courseCode . ($ecLabel !== '' ? '/' . $ecLabel : '');
    ?>
      <button type="button"
              class="btn btn-sm <?= $i===0 ? 'btn-primary' : 'btn-outline-primary' ?> me-2 mb-2 bundle-chip"
              data-cid="<?= $cid ?>">
        <?= h($chipText) ?>
      </button>
    <?php endforeach; ?>
  </div>
<?php endif; ?>

  <!-- Bundle blocks -->
  <?php foreach ($bundle_children as $i => $bc): $cid = (int)$bc['id']; ?>
    <div class="bundle-block <?= $i===0 ? '' : 'd-none' ?>" data-cid="<?= $cid ?>">

      <!-- Lesson Plan -->
      <div class="card mb-3">
        <div class="card-header"><h6 class="fw-bold m-0">Lesson Plan</h6></div>
        <div class="card-body p-0">
          <table class="table m-0">
            <thead class="table-light">
              <tr><th style="width:60px">#</th><th>Lesson Title</th></tr>
            </thead>
            <tbody>
              <?php $titles = $child_lessons[$cid] ?? []; ?>
              <?php if (!empty($titles)): ?>
                <?php foreach ($titles as $idx => $title): ?>
                  <tr><td><?= $idx+1 ?></td><td><?= h($title) ?></td></tr>
                <?php endforeach; ?>
              <?php else: ?>
                <tr><td colspan="2" class="text-center">No lessons added.</td></tr>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </div>

      <!-- Evaluation Attempts -->
<?php
// ==== Evaluation Attempts (MARKS_VALIDATION logic) ====

// Per-course EC numbers (for student_numbers matching)
$ref = $refs_by_course[$cid] ?? ['ec1'=>'','ec2'=>''];

// Build rows using Marks Validation algorithm (Final exam per Unit No + last attempt)
$attemptRows = ec_build_eval_attempts_like_marks_validation(
  $mysqli,
  (int)$student_id,
  $student,           // full studentss row already loaded
  (int)$cid,          // child course id
  $ref                // ec1/ec2
);

// Map to UI table keys
$planRows = [];
foreach ($attemptRows as $r) {
  $score = $r['score'];
  $total = $r['total'];
  $marksText = (is_numeric($score) && is_numeric($total) && (float)$total > 0)
    ? ((float)$score) . " / " . ((float)$total)
    : (is_numeric($score) ? (string)$score : '-');

  $planRows[] = [
    'module' => (string)($r['module_name'] ?? '-'),
    'method' => (string)($r['evaluation_method'] ?? 'Online Exam'),
    'type'   => (string)($r['evaluation_type'] ?? 'Final'),
    'date'   => (string)($r['date_evaluated'] ?? '-'),
    'marks'  => $marksText,
    'grade'  => (string)($r['grade'] ?? '-'),
    'result' => (string)($r['result'] ?? '-'),
  ];
}
?>



      <div class="card mb-3">
        <div class="card-header d-flex justify-content-between align-items-center">
          <h6 class="fw-bold m-0">Evaluation Attempts</h6>
          <span class="text-muted small">ATTEMPT 01</span>
        </div>
        <div class="card-body p-0">
          <table class="table table-bordered m-0 align-middle">
            <thead class="table-light">
              <tr>
                <th style="width:34%">Module</th>
                <th style="width:18%">Evaluation Method</th>
                <th style="width:10%">Type</th>
                <th style="width:16%">Date Evaluated</th>
                <th style="width:10%">Grade</th>
                <th style="width:12%">Result</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($planRows)): ?>
                <tr><td colspan="6" class="text-center text-muted">No modules found.</td></tr>
              <?php else: ?>
                <?php foreach ($planRows as $row): ?>
                  <tr>
                    <td><?= h($row['module']) ?></td>
                    <td><?= h($row['method']) ?></td>
                    <td><?= h($row['type']) ?></td>
                    <td><?= h($row['date']) ?></td>
                    <td><?= h($row['grade']) ?></td>
                    <td><?= h($row['result']) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </div>

    </div>
  <?php endforeach; ?>

<script>
document.addEventListener("click", function(e){
  const btn = e.target.closest(".bundle-chip");
  if (!btn) return;

  const cid = btn.getAttribute("data-cid");

  document.querySelectorAll("#course .bundle-chip").forEach(b=>{
    b.classList.remove("btn-primary");
    b.classList.add("btn-outline-primary");
  });
  btn.classList.remove("btn-outline-primary");
  btn.classList.add("btn-primary");

  document.querySelectorAll("#course .bundle-block").forEach(block=>{
    block.classList.toggle("d-none", block.getAttribute("data-cid") !== cid);
  });
});
</script>



      <script>
        document.querySelectorAll('.bundle-chip').forEach(btn=>{
          btn.addEventListener('click', ()=>{
            const cid = btn.getAttribute('data-cid');
            document.querySelectorAll('.bundle-chip').forEach(b=>{
              b.classList.remove('btn-primary'); b.classList.add('btn-outline-primary');
            });
            btn.classList.remove('btn-outline-primary'); btn.classList.add('btn-primary');
            document.querySelectorAll('.bundle-block').forEach(p=>{
              p.classList.toggle('d-none', p.getAttribute('data-cid') !== cid);
            });
          });
        });
      </script>

      <?php
      // Certification
      $certRows = [];
      if (tableExists($mysqli,'student_certifications')) {
        $st = $mysqli->prepare("SELECT provider, certification, certificate_name, status, name_verified, updated_at FROM student_certifications WHERE student_id=? ORDER BY id ASC");
        $st->bind_param('i',$student_id); $st->execute();
        if (method_exists($st,'get_result')) { $rs = $st->get_result(); while($row = $rs->fetch_assoc()) $certRows[] = $row; }
        $st->close();
      }
      if (!$certRows && tableExists($mysqli,'student_verifications')) {
        $st = $mysqli->prepare("SELECT certificate_name, verified FROM student_verifications WHERE student_id=? LIMIT 1");
$st->bind_param('i',$student_id); $st->execute();
$v = method_exists($st,'get_result') ? $st->get_result()->fetch_assoc() : stmt_fetch_one_assoc($st);
$st->close();

        if ($v && !empty($v['certificate_name'])) {
          $certRows[] = [
            'provider'=>'GA','certification'=>'GATEHOUSE Certification',
            'certificate_name'=>$v['certificate_name'],'status'=>'Pending',
            'name_verified'=>(int)($v['verified'] ?? 0),'updated_at'=>null
          ];
        }
      }
      ?>
      <div class="card mb-3">
        <div class="card-header"><h6 class="fw-bold m-0"><i class="bi bi-award me-1"></i> Certification</h6></div>
        <div class="card-body p-0">
          <table class="table table-bordered m-0 align-middle text-start">
            <thead class="table-light">
              <tr><th style="width:16%">Provider</th><th style="width:24%">Certification</th><th>Name on the Certificate</th><th style="width:15%">Status</th></tr>
            </thead>
            <tbody>
              <?php if ($certRows): foreach ($certRows as $c): ?>
                <tr>
                  <td><?= h($c['provider'] ?? '-') ?></td>
                  <td><?= h($c['certification'] ?? '-') ?></td>
                  <td>
                    <?= h($c['certificate_name'] ?? '-') ?>
                    <?php if (!empty($c['name_verified'])): ?><i class="bi bi-check-circle-fill text-success ms-1" title="Name verified"></i><?php endif; ?>
                  </td>
                  <td><?= h($c['status'] ?? 'Pending') ?></td>
                </tr>
              <?php endforeach; else: ?>
                <tr><td colspan="4" class="text-center text-muted">No certification records yet.</td></tr>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </div>

<?php
$letter_batch_id = ec_get_student_batch_id_for_course($mysqli, (int)$student_id, (int)$cid);
?>
      <!-- Letters -->
      <div class="card mt-3 letters-panel">
        <div class="card-header d-flex justify-content-between align-items-center">
          <h6 class="fw-bold m-0"><span><i class="bi bi-grid-3x3-gap me-1"></i> Course Letters</span></h6>
          <button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#lettersCollapse" aria-expanded="true">
            <i class="bi bi-chevron-down"></i>
          </button>
        </div>
        <div id="lettersCollapse" class="collapse show">
          <div class="card-body">
            <div class="row g-3">
              <div class="col-md-4">
                <a class="letter-card" target="_blank" href="/edenrms/pages/letters/enrollment.php?student_id=<?= (int)$student_id ?>&course_id=<?= (int)$cid ?>&batch_id=<?= (int)$letter_batch_id ?>">
                  <div class="lc-head">Enrollment Confirmation</div>
                  <ul class="lc-points">
                    <li><i class="bi bi-check-circle text-success"></i>Official confirmation</li>
                    <li><i class="bi bi-check-circle text-success"></i>Batch &amp; dates</li>
                  </ul>
                </a>
              </div>
              <div class="col-md-4">
                <a class="letter-card" target="_blank" href="/edenrms/pages/letters/following.php?student_id=<?= (int)$student_id ?>&course_id=<?= (int)$cid ?>&batch_id=<?= (int)$letter_batch_id ?>">
                  <div class="lc-head">Course Attendance / Following Letter</div>
                  <ul class="lc-points">
                    <li><i class="bi bi-check-circle text-success"></i>Currently following</li>
                    <li><i class="bi bi-x-circle text-danger"></i>No grading rubrics</li>
                  </ul>
                </a>
              </div>
              <div class="col-md-4">
                <a class="letter-card" target="_blank" href="/edenrms/pages/letters/completion.php?student_id=<?= (int)$student_id ?>&course_id=<?= (int)$cid ?>&batch_id=<?= (int)$letter_batch_id ?>">
                  <div class="lc-head">Completion &amp; Results Summary</div>
                  <ul class="lc-points">
                    <li><i class="bi bi-check-circle text-success"></i>With marks</li>
                    <li><i class="bi bi-check-circle text-success"></i>With grades</li>
                  </ul>
                </a>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div><!-- /course -->

    <!-- PAYMENTS -->
    <div class="tab-pane fade" id="payments">
      <div class="row g-3 mb-2">
        <div class="col-lg-6">
          <div class="kv-group">
            <div class="kv-row"><div class="k">Payment Status</div>
              <div class="v">
  <span class="badge <?= h(match($payment_status){
    'Completed' => 'bg-success',
    'Paid'      => 'bg-success',
    'Overdue'   => 'bg-danger',
    'N/A'       => 'bg-secondary',
    default     => 'bg-secondary',
  }) ?>"><?= h($payment_status) ?></span>
</div>
            </div>
            <div class="kv-row"><div class="k">Payment Plan</div>
              <div class="v"><?= h(($plan['plan_name'] ?? ($plan['name'] ?? '')) ?: '-') ?></div>
            </div>
          </div>
        </div>
        <div class="col-lg-6">
          <div class="kv-group">
            <div class="kv-row"><div class="k">Payment Method</div><div class="v"><?= h($selected_method ?: '-') ?></div></div>
            <div class="kv-row"><div class="k">Promotion Plan</div>
              <div class="v">
                <?= h($promotion_plan ?: ($discount_lkr > 0 ? 'Discount' : '-')) ?>
                <?php if ($discount_lkr > 0): ?><div class="small text-muted">Total Saving - <?= nf($discount_lkr) ?> LKR</div><?php endif; ?>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Installment Plan -->
      <div id="installmentPlanBlock" class="card mb-3">
        <div class="card-header d-flex justify-content-between align-items-center">
          <h6 class="fw-bold m-0">Installment Plan</h6>
          <button id="btnCustomizePlan"
        class="btn btn-sm btn-outline-primary"
        type="button"
        data-target="#<?= $customModalId ?>">
  <i class="bi bi-sliders"></i> Customize Installment Plan
</button>

        </div>
        <div class="card-body p-0">
          <table class="table table-bordered text-center m-0">
            <thead><tr><th>#</th><th>Course Fee</th><th>Reg Fee</th><th>Cert Fee</th><th>Due Date</th></tr></thead>
            <tbody id="installmentTbody">
<?php if (!empty($installments)): ?>
<?php
  $__course_pool = max(0.0, $paid_course);
  $__reg_pool    = max(0.0, $paid_reg_lkr);
  $__usd_pool    = max(0.0, $paid_uka);
  $__disc_rem    = max(0.0, (float)$discount_lkr);

  $sumC2 = 0.0; $sumR2 = 0.0; $sumU2 = 0.0;
  foreach ($installments as $__tmp) {
    $sumC2 += (float)($__tmp['course_fee_lkr'] ?? 0);
    $sumR2 += (float)($__tmp['registration_fee_lkr'] ?? 0);
    $sumU2 += (float)($__tmp['certificate_fee_usd'] ?? 0);
  }
?>

<?php foreach ($installments as $idx => $ins):

  $c_raw = (float)($ins['course_fee_lkr'] ?? 0);
  $r     = (float)($ins['registration_fee_lkr'] ?? 0);
  $u     = (float)($ins['certificate_fee_usd'] ?? 0);

  // discount apply only for display (keep raw too)
  $disc_here = 0.0;
  if ($__disc_rem > 0 && $c_raw > 0) { $disc_here = min($__disc_rem, $c_raw); $__disc_rem -= $disc_here; }
  $c_net = max(0.0, $c_raw - $disc_here);

  // paid pools use NET values for tooltip/balance display
  $paid_course_here = min($c_net, $__course_pool); $__course_pool -= $paid_course_here;
  $paid_reg_here    = min($r,     $__reg_pool);    $__reg_pool    -= $paid_reg_here;
  $paid_usd_here    = min($u,     $__usd_pool);    $__usd_pool    -= $paid_usd_here;

  $bal_course = max(0.0, round($c_net - $paid_course_here, 2));
  $bal_reg    = max(0.0, round($r     - $paid_reg_here,    2));
  $bal_usd    = max(0.0, round($u     - $paid_usd_here,    2));

  $tt_course = 'Already Paid - '.nf($paid_course_here).'&#10;Balance Fee - '.nf($bal_course);
  $tt_reg    = 'Already Paid - '.nf($paid_reg_here  ).'&#10;Balance Fee - '.nf($bal_reg);
  $tt_usd    = 'Already Paid - '.nf($paid_usd_here  ).'&#10;Balance Fee - '.nf($bal_usd);

  $icon_course = $c_net > 0 ? ($bal_course <= 0.00
    ? '<i class="bi bi-check-circle-fill text-success ms-1" data-bs-toggle="tooltip" title="'.$tt_course.'"></i>'
    : '<i class="bi bi-info-circle text-muted ms-1" data-bs-toggle="tooltip" title="'.$tt_course.'"></i>') : '';

  $icon_reg = $r > 0 ? ($bal_reg <= 0.00
    ? '<i class="bi bi-check-circle-fill text-success ms-1" data-bs-toggle="tooltip" title="'.$tt_reg.'"></i>'
    : '<i class="bi bi-info-circle text-muted ms-1" data-bs-toggle="tooltip" title="'.$tt_reg.'"></i>') : '';

  $icon_usd = $u > 0 ? ($bal_usd <= 0.00
    ? '<i class="bi bi-check-circle-fill text-success ms-1" data-bs-toggle="tooltip" title="'.$tt_usd.'"></i>'
    : '<i class="bi bi-info-circle text-muted ms-1" data-bs-toggle="tooltip" title="'.$tt_usd.'"></i>') : '';

  $no  = (int)($ins['installment_no'] ?? ($idx + 1));
  $due = trim((string)($ins['due_date'] ?? ''));
  $dueISO = preg_match('/^\d{4}-\d{2}-\d{2}$/', $due) ? $due : '';
?>
<tr class="ip-row"
    data-no="<?= $no ?>"
    data-course="<?= number_format($c_net, 2, '.', '') ?>"
    data-course-raw="<?= number_format($c_raw, 2, '.', '') ?>"
    data-reg="<?= number_format($r, 2, '.', '') ?>"
    data-cert="<?= number_format($u, 2, '.', '') ?>"
    data-date="<?= $dueISO ?>">
  <td><?= $no ?></td>
  <td><?= nf($c_net) ?><?= $icon_course ?></td>
  <td><?= nf($r) ?><?= $icon_reg ?></td>
  <td><?= nf($u) ?><?= $icon_usd ?></td>
  <td><?= h($ins['due_date'] ?? '') ?></td>
</tr>
<?php endforeach; ?>

<?php if ($discount_lkr > 0): ?>
<tr class="table-warning">
  <td class="text-end text-muted">—</td>
  <td class="text-danger">-<?= nf($discount_lkr) ?></td>
  <td>0.00</td>
  <td>0.00</td>
  <td class="text-muted">Discount</td>
</tr>
<?php endif; ?>

<?php if ($extra_fee_lkr > 0): ?>
<tr class="table-warning">
  <td class="text-end text-muted">—</td>
  <td class="text-success"><?= nf($extra_fee_lkr) ?></td>
  <td>0.00</td>
  <td>0.00</td>
  <td class="text-muted">Extra Fee(s)</td>
</tr>
<?php endif; ?>

<tr class="table-light fw-semibold">
  <td class="text-end">Net</td>
  <td><?= nf(max(0, $sumC2 - $discount_lkr + $extra_fee_lkr)) ?></td>
  <td><?= nf($sumR2) ?></td>
  <td><?= nf($sumU2) ?></td>
  <td></td>
</tr>

<?php else: ?>
<tr><td colspan="5" class="text-center">No installments configured.</td></tr>
<?php endif; ?>
</tbody>


          </table>
        </div>
      </div>

      <!-- Payment Plan -->
      <div class="table-responsive border rounded p-3 bg-white shadow-sm mt-4">
        <div class="d-flex justify-content-between align-items-center mb-2">
          <h6 class="fw-bold m-0">Payment Plan</h6>
          <div class="d-flex gap-2">
            <button type="button" class="btn btn-sm btn-success"  onclick="openAddDiscount()">+ Add Discount</button>
            <button type="button" class="btn btn-sm btn-outline-danger" onclick="openAddExtra()">+ Add Extra Fee(s)</button>
          </div>
        </div>

        <table class="table table-bordered align-middle m-0" id="planTable">
          <tbody>
              
            <tr><th>Course Fee</th><td id="pp_course_lkr"><?= nf($course_fee_lkr) ?> LKR</td><td>0.00 USD</td></tr>
            <tr id="row_reg_fee_lkr"<?= $reg_fee_lkr > 0 ? '' : ' class="d-none"' ?>><th>Registration Fee</th><td id="pp_reg_lkr"><?= nf($reg_fee_lkr) ?> LKR</td><td>0.00 USD</td></tr>
            <tr id="row_cert_fee_usd"<?= $cert_fee_usd > 0 ? '' : ' class="d-none"' ?>><th>Certificate Fee</th><td id="pp_cert_lkr">0.00</td><td id="pp_cert_usd"><?= nf($cert_fee_usd) ?> USD</td></tr>
            <tr class="table-secondary"><th>Sub Total</th><td id="pp_sub_lkr"><?= nf($course_fee_lkr + $reg_fee_lkr) ?> LKR</td><td id="pp_sub_usd"><?= nf($cert_fee_usd) ?> USD</td></tr>
            <tr id="row_late_charges"<?= $late_charges > 0 ? '' : ' class="d-none"' ?>><th>Late Charges</th><td id="pp_late_lkr"><?= nf($late_charges) ?></td><td>0.00</td></tr>
            <tr id="row_discount"<?= $discount_lkr>0?'':' class="d-none"' ?>><th>Discount</th><td id="pp_disc_lkr"><?= nf($discount_lkr) ?> LKR</td><td>0.00 USD</td></tr>
<tr id="row_extra"<?= $extra_fee_lkr > 0 ? '' : ' class="d-none"' ?>>
  <th>Extra Fee(s)</th>
  <td id="pp_extra_lkr"><?= nf($extra_fee_lkr) ?> LKR</td>
  <td>0.00 USD</td>
</tr>
<tr class="table-primary fw-bold"><th>Total Payable</th><td id="pp_total_lkr"><?= nf($total_payable_lkr) ?> LKR</td><td id="pp_total_usd"><?= nf($cert_fee_usd) ?> USD</td></tr>
           <tr class="table-success fw-bold">
  <th>Already Paid Total</th>
  <td><?= nf($already_paid_lkr) ?> LKR</td>
  <td><?= nf($paid_uka) ?> USD</td>
</tr>
            <tr><th>Total Outstanding</th><td id="pp_out_lkr"><?= nf($outstanding_lkr) ?> LKR</td><td id="pp_out_usd"><?= nf(max(0, $cert_fee_usd - $paid_uka)) ?> USD</td></tr>
          </tbody>
        </table>
      </div>

<!-- Payment History -->
<div class="card mt-3 payment-history-card">
  <div class="card-header payment-history-head d-flex align-items-center justify-content-between">
    <h6 class="m-0 fw-bold">
      <i class="bi bi-grid-3x3-gap-fill me-2"></i>Payment History
    </h6>
  </div>

  <div class="card-body p-0">
    <div class="table-responsive">
      <table class="table align-middle m-0 payment-history-table">
        <thead>
          <tr>
            <th style="width:120px;">Status</th>
            <th style="width:170px;">Date Paid</th>
            <th>Branch</th>
            <th>Payment Method</th>
            <th style="width:140px;" class="text-end">Amount</th>
            <th>Cashier</th>
            <th style="width:130px;" class="text-center">Action</th>
          </tr>
        </thead>

        <tbody>
<?php if (!empty($payments)): ?>
  <?php foreach ($payments as $pay): ?>
    <?php
      $amount = (float)($pay['amount'] ?? 0);

      $date_paid_raw = trim((string)($pay['date_paid'] ?? ''));
      $date_main = $date_paid_raw ? date('Y-m-d', strtotime($date_paid_raw)) : '-';
      $date_sub  = $date_paid_raw ? date('h:i:s A', strtotime($date_paid_raw)) : '';

      $method_raw = trim((string)($pay['payment_method'] ?? $pay['method'] ?? '-'));
      $method_key = strtolower(preg_replace('/\s+/', '_', $method_raw));
      $method_map = [
        'cash'          => 'Cash',
        'bank'          => 'Bank Transfer',
        'bank_transfer' => 'Bank Transfer',
        'card'          => 'Card',
        'visa'          => 'Card',
        'master'        => 'Card',
        'online'        => 'Online',
      ];
      $method_label = $method_map[$method_key] ?? ($method_raw !== '' ? $method_raw : '-');

      /* IMPORTANT: only DB-saved values */
      $branch_label = trim((string)($pay['branch_name'] ?? ''));
if ($branch_label === '') $branch_label = '-';

$cashier_label = trim((string)($pay['cashier_name'] ?? ''));
if ($cashier_label === '') $cashier_label = '-';

      $status_text  = 'Paid';
      $status_class = 'paid';
    ?>
    <tr>
      <td class="text-center">
        <span class="ph-badge <?= h($status_class) ?>"><?= h($status_text) ?></span>
      </td>

      <td>
        <div class="ph-date-main"><?= h($date_main) ?></div>
        <div class="ph-date-sub"><?= h($date_sub) ?></div>
      </td>

      <td><?= h($branch_label) ?></td>

      <td><?= h($method_label) ?></td>

      <td class="text-end fw-semibold"><?= nf($amount) ?></td>

      <td><?= h($cashier_label) ?></td>

      <td class="text-center">
        
        <a class="btn btn-sm ph-btn-print"
                     target="_blank"
                     href="/edenrms/pages/receipt.php?payment_id=<?= (int)$pay['id'] ?>&auto=1">
                    <i class="bi bi-printer"></i>
                  </a>
      </td>
    </tr>
  <?php endforeach; ?>
<?php else: ?>
  <tr>
    <td colspan="7" class="text-center text-muted py-4">No payment history found.</td>
  </tr>
<?php endif; ?>
</tbody>
      </table>
    </div>
  </div>
</div>

    <div class="card-footer text-end bg-white">
    <?php if (($payment_status ?? '') !== 'Completed' && ($out_lkr ?? 0) > 0.009): ?>
      <button class="btn btn-success btn-sm px-3"
              onclick="openAddPayment(
  <?= (int)$student_id ?>,
  <?= (int)($plan['id'] ?? 0) ?>,
  <?= (int)($course_id ?: $resolved_course_id ?: ($student['course_id'] ?? 0)) ?>
)">
        <i class="bi bi-plus-circle me-1"></i>Add Payment
      </button>
    <?php endif; ?>
  </div>
</div><!-- /payments -->

    <!-- OTHER -->
    <div class="tab-pane fade" id="other" role="tabpanel" aria-labelledby="other-tab">
      <!-- LMS Login Details -->
      <div class="card shadow-sm mb-3">
        <div class="card-header bg-light d-flex align-items-center justify-content-between">
          <div><i class="bi bi-laptop"></i> LMS Login Details</div>
        </div>
        <div class="card-body p-2">
          <div class="table-responsive">
            <table class="table table-sm table-bordered mb-2 align-middle">
              <thead class="table-secondary">
                <tr><th>Academic Email (Username)</th><th>Password</th><th>Status</th><th>SMS Sent To</th><th>Created On</th><th>Resets</th></tr>
              </thead>
              <tbody>
                <tr>
                  <td id="lmsEmail"><?= $academic_email !== '' ? h($academic_email) : '<span class="text-muted">Not created</span>' ?></td>
                 <td id="lmsPassword">
  <span id="lmsPasswordMasked">••••••••</span>

  <?php if ($academic_plain_password !== ''): ?>
    <!-- We have plain password – keep it hidden but revealable -->
    <code id="lmsPasswordPlain" class="d-none"><?= h($academic_plain_password) ?></code>
  <?php elseif ($academic_hash !== ''): ?>
    <!-- No plain, only hash – still allow “eye” if you want to see raw value -->
    <code id="lmsPasswordPlain" class="d-none"><?= h($academic_hash) ?></code>
  <?php else: ?>
    <!-- Nothing yet – keep empty, but UI still shows bullets + eye -->
    <code id="lmsPasswordPlain" class="d-none"></code>
  <?php endif; ?>

  <button type="button"
          class="btn btn-sm btn-outline-secondary ms-1"
          id="btnTogglePw">
    <i class="bi bi-eye"></i>
  </button>
</td>
                 <td>
    <div class="d-flex align-items-center gap-2">
     <?php
// Resolve 3-way status: 1=Active, 0=Inactive, 2=Suspended
$lms_status_val = 1; // default Active

if ($has_lms_active) {
    $res = $mysqli->query("SELECT lms_status FROM studentss WHERE id=".(int)$student_id);
    if ($res && $row = $res->fetch_assoc()) {
        $raw_s = strtolower(trim((string)($row['lms_status'] ?? 'active')));
        $lms_status_val = match($raw_s) {
            'inactive' => 0,
            'suspended' => 2,
            default => 1
        };
    }
}

$statusMap = [
    1 => ['label'=>'Active',    'class'=>'bg-success'],
    0 => ['label'=>'Inactive',  'class'=>'bg-secondary'],
    2 => ['label'=>'Suspended', 'class'=>'bg-danger'],
];

$cur = $statusMap[$lms_status_val] ?? $statusMap[1];
?>

<span id="lmsStatusBadge" class="badge <?= $cur['class'] ?>">
    <?= htmlspecialchars($cur['label']) ?>
</span>

<?php if ($has_lms_active): ?>
    <select id="lmsStatusSelect" class="form-select form-select-sm w-auto" style="min-width:110px">
        <option value="1" <?= $lms_status_val === 1 ? 'selected' : '' ?>>Active</option>
        <option value="0" <?= $lms_status_val === 0 ? 'selected' : '' ?>>Inactive</option>
        <option value="2" <?= $lms_status_val === 2 ? 'selected' : '' ?>>Suspended</option>
    </select>
<?php else: ?>
    <span class="text-muted small">(no lms_active column)</span>
<?php endif; ?>
                  <td><?= $student_mobile !== '' ? h($student_mobile) : '<span class="text-muted">—</span>' ?></td>
                  <td><?= $created_on ? h(substr($created_on,0,10)) : '<span class="text-muted">—</span>' ?></td>
                  <td id="lmsResets"><?= (int)$academic_reset_count ?></td>
                </tr>
              </tbody>
            </table>
          </div>
          <div class="d-flex gap-2">
    <button id="btnLmsAssign" class="btn btn-sm btn-success"><i class="bi bi-plus-lg"></i> Create / Activate</button>
    <button id="btnLmsReset" class="btn btn-sm btn-primary"><i class="bi bi-arrow-repeat"></i> Reset Password</button>
</div>
          <small class="text-muted d-block mt-2">
            Note: Passwords are stored as secure hashes. If you add an optional column
            <code>studentss.academic_plain_password</code>, we’ll show the one-time value after reset.
          </small>
        </div>
      </div>

      <!-- Registration Checklist -->
      <div class="card shadow-sm">
        <div class="card-header"><h6 class="fw-bold m-0"><i class="bi bi-list-check me-1"></i> Registration Checklist</h6></div>
        <div class="card-body">
          <?php
          $chk = [];
          if (tableExists($mysqli,'student_checklist')) {
            $rs = $mysqli->prepare("SELECT item_key,is_done FROM student_checklist WHERE student_id=?");
            $rs->bind_param('i',$student_id); $rs->execute();
            if (method_exists($rs,'get_result')) {
              $rset=$rs->get_result(); while($row=$rset->fetch_assoc()){ $chk[$row['item_key']] = (int)$row['is_done'] === 1; }
            } else {
              $rows = stmt_fetch_all_assoc($rs);
              foreach ($rows as $row) { $chk[$row['item_key']] = (int)$row['is_done'] === 1; }
            }
            $rs->close();
          }
          ?>
          <div class="form-check mb-2"><input class="form-check-input" type="checkbox" id="c1" <?= !empty($chk['c1'])?'checked':'' ?>><label class="form-check-label" for="c1">Received the registration agreement and it is clear.</label></div>
          <div class="form-check mb-2"><input class="form-check-input" type="checkbox" id="c2" <?= !empty($chk['c2'])?'checked':'' ?>><label class="form-check-label" for="c2">Was able to login to Student Portal.</label></div>
          <div class="form-check mb-2"><input class="form-check-input" type="checkbox" id="c3" <?= !empty($chk['c3'])?'checked':'' ?>><label class="form-check-label" for="c3">Has got the text books and/or other resources necessary.</label></div>
          <div class="form-check mb-2"><input class="form-check-input" type="checkbox" id="c4" <?= !empty($chk['c4'])?'checked':'' ?>><label class="form-check-label" for="c4">Is satisfied with the service received.</label></div>
          <div class="form-check mb-2"><input class="form-check-input" type="checkbox" id="c5" <?= !empty($chk['c5'])?'checked':'' ?>><label class="form-check-label" for="c5">Student Photograph uploaded.</label></div>
          <div class="form-check mb-4"><input class="form-check-input" type="checkbox" id="c6" <?= !empty($chk['c6'])?'checked':'' ?>><label class="form-check-label" for="c6">Name verification completed.</label></div>
          <div class="text-end"><button class="btn btn-success" onclick="saveChecklist(<?= (int)$student_id ?>)">Confirm and Update</button></div>
        </div>
      </div>
    </div><!-- /other -->

  </div><!-- /.tab-content -->
</div><!-- /.container -->

<!-- Add Payment Modal -->
<div class="modal fade"
     id="addPaymentModal"
     data-course-id="<?= (int)($course_id ?: $resolved_course_id ?: ($student['course_id'] ?? 0)) ?>"
     data-course-balance="<?= $course_balance_lkr ?>"
     data-reg-balance="<?= $reg_balance_lkr ?>"
     data-ukawards-balance="<?= $uka_balance_usd ?>"
data-extra-balance="<?= $extra_fee_lkr ?>">
  <div class="modal-dialog modal-xl modal-dialog-centered">
    <form class="modal-content addpay-modal-content border-0" id="addPaymentForm">
      <div class="modal-header addpay-header border-0">
        <div class="d-flex align-items-center gap-3">
          <div class="addpay-icon-wrap">
            <i class="bi bi-wallet2"></i>
          </div>
          <div>
            <h5 class="modal-title mb-1">Add Payment</h5>
            <div class="addpay-subtitle">Record payment details in a cleaner and organized way</div>
          </div>
        </div>
        <button type="button" class="btn-close addpay-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>

      <div class="modal-body addpay-body">
        <input type="hidden" name="student_id" id="ap_student_id" value="<?= (int)$student_id ?>">
<input type="hidden" name="plan_id" id="ap_plan_id" value="<?= (int)($plan['id'] ?? 0) ?>">
<input type="hidden" name="course_id" id="ap_course_id" value="<?= (int)($course_id ?: $resolved_course_id ?: ($student['course_id'] ?? 0)) ?>">

        <div class="row g-4 align-items-stretch">
          <!-- LEFT -->
          <div class="col-lg-7">
            <div class="addpay-card h-100">
              <div class="addpay-card-head">
                <div>
                  <h6 class="mb-1"><i class="bi bi-bar-chart-line me-2"></i>Balance Summary</h6>
                  <p class="mb-0">Outstanding amounts and fee breakdown</p>
                </div>
              </div>

              <div class="addpay-card-body pt-0">
                <div class="table-responsive addpay-summary-table-wrap">
                  <table class="table addpay-summary-table align-middle mb-0">
                    <thead>
                      <tr>
                        <th></th>
                        <th class="text-center">LKR</th>
                        <th class="text-center">USD</th>
                      </tr>
                    </thead>
                   <tbody>
  <?php if ($course_balance_lkr > 0.009): ?>
    <tr>
      <td>Course Fee</td>
      <td class="text-end"><?= nf($course_balance_lkr) ?></td>
      <td class="text-end">0.00</td>
    </tr>
  <?php endif; ?>

  <?php if ($reg_balance_lkr > 0.009): ?>
    <tr>
      <td>Registration Fee</td>
      <td class="text-end"><?= nf($reg_balance_lkr) ?></td>
      <td class="text-end">0.00</td>
    </tr>
  <?php endif; ?>

  <tr>
    <td>UK Awards Fee</td>
    <td class="text-end">0.00</td>
    <td class="text-end"><?= nf($uka_balance_usd) ?></td>
  </tr>
  
<?php if ((float)$extra_fee_lkr > 0.009): ?>
<tr>
  <td>Extra Fee(s)</td>
  <td class="text-end"><?= nf($extra_fee_lkr) ?></td>
  <td class="text-end">0.00</td>
</tr>
<?php endif; ?>

  <tr class="table-light fw-semibold">
  <td>Sub Total</td>
  <td class="text-end"><?= nf($balance_subtotal_lkr + $extra_fee_lkr) ?></td>
  <td class="text-end"><?= nf($balance_subtotal_usd) ?></td>
</tr>

  <?php if ((float)$late_charges > 0.009): ?>
    <tr>
      <td>Late Charges (Penalty)</td>
      <td class="text-end"><?= nf($late_charges) ?></td>
      <td class="text-end">0.00</td>
    </tr>
  <?php endif; ?>

  <tr class="fw-bold">
  <td>Total Outstanding</td>
  <td class="text-end"><?= nf($balance_subtotal_lkr + $extra_fee_lkr + max(0.0, (float)$late_charges)) ?></td>
  <td class="text-end"><?= nf($balance_subtotal_usd) ?></td>
</tr>

  <tr>
    <td>Accumulated Dues</td>
    <td class="text-end">0.00</td>
    <td class="text-end">0.00</td>
  </tr>
</tbody>
                  </table>
                </div>

                <!-- Items table -->
                <div id="ap_items_wrap" class="mt-4 addpay-items-box d-none">
                  <div class="d-flex justify-content-between align-items-center flex-wrap gap-2 px-3 pt-3 pb-2">
                    <div class="fw-bold text-dark">Payment Items</div>
                    <div class="small text-muted">Multiple fee items can be added before saving</div>
                  </div>

                  <div class="table-responsive">
                    <table class="table table-borderless addpay-items-table mb-0 text-center align-middle" id="ap_items_table">
                      <thead>
                        <tr>
                          <th style="width:34%">Fee Type</th>
                          <th style="width:16%">Currency</th>
                          <th style="width:22%">Amount</th>
                          <th style="width:18%">Method</th>
                          <th style="width:10%"></th>
                        </tr>
                      </thead>
                      <tbody></tbody>
                      <tfoot>
                        <tr>
                          <td colspan="2" class="text-end fw-bold">Total LKR</td>
                          <td class="fw-bold text-center" id="ap_total_lkr">0.00</td>
                          <td colspan="2"></td>
                        </tr>
                        <tr>
                          <td colspan="2" class="text-end fw-bold">Total USD</td>
                          <td class="fw-bold text-center" id="ap_total_usd">0.00</td>
                          <td colspan="2"></td>
                        </tr>
                      </tfoot>
                    </table>
                  </div>
                </div>

              </div>
            </div>
          </div>

          <!-- RIGHT -->
          <div class="col-lg-5">
            <div class="addpay-card h-100">
              <div class="addpay-card-head">
                <div>
                  <h6 class="mb-1"><i class="bi bi-pencil-square me-2"></i>Payment Entry</h6>
                  <p class="mb-0">Enter details and add payment items</p>
                </div>
              </div>

              <div class="addpay-card-body">
                <div class="mb-3">
                  <label class="form-label addpay-label">Fee Type <span class="text-danger">*</span></label>
                  <select class="form-select addpay-input" id="ap_fee_type">
                    <option value="" selected disabled>Select an Option</option>
                    <option>Course Fee</option>
                    <option>Registration Fee</option>
                    <option>Extra Fee(s)</option>
                    <option>UK Awards Fee</option>
                  </select>
                </div>

                <div class="mb-3">
                  <label class="form-label addpay-label">Amount <span class="text-danger">*</span></label>
                  <div class="input-group addpay-amount-group">
                    <select class="form-select addpay-input addpay-currency" id="ap_currency">
                      <option value="LKR" selected>LKR</option>
                      <option value="USD">USD</option>
                    </select>
                    <input type="number" step="0.01" min="0" class="form-control addpay-input" id="ap_amount" placeholder="0.00">
                    <button type="button" class="btn addpay-add-btn" id="ap_add_btn" title="Add">
                      <i class="bi bi-plus-lg"></i>
                    </button>
                  </div>
                </div>

                <div class="mb-3">
                  <label class="form-label addpay-label">Payment Method</label>
                  <select class="form-select addpay-input" id="ap_method">
                    <option>Cash</option>
                    <option>Bank Transfer</option>
                    <option>Card</option>
                    <option>Online</option>
                  </select>
                </div>

                <div class="mb-3">
                  <label class="form-label addpay-label">Reference No <span class="text-muted fw-normal">(optional)</span></label>
                  <input type="text" class="form-control addpay-input" id="ap_ref" placeholder="e.g., slip/txn no">
                </div>

                <div class="mb-3">
                  <label class="form-label addpay-label">Notes <span class="text-muted fw-normal">(optional)</span></label>
                  <textarea rows="3" class="form-control addpay-input" id="ap_notes" placeholder="Any note for this payment"></textarea>
                </div>

                <div class="addpay-alert">
                  <i class="bi bi-info-circle-fill me-2"></i>
                  You can add multiple items using the plus button before saving. The final payment will be saved properly based on the entered totals.
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="modal-footer addpay-footer border-0">
        <div class="me-auto small text-muted fw-medium" id="ap_hint"></div>
        <button type="button" class="btn addpay-btn-secondary" data-bs-dismiss="modal">Close</button>
        <button class="btn addpay-btn-primary" type="submit" id="ap_save_btn">
          <i class="bi bi-save2 me-1"></i> Save Payment
        </button>
      </div>
    </form>
  </div>
</div>

<style>
  #addPaymentModal .modal-dialog{
    max-width: 1180px;
  }

  #addPaymentModal .addpay-modal-content{
    border-radius: 22px;
    overflow: hidden;
    background: #f8fafc;
    box-shadow: 0 25px 70px rgba(15, 23, 42, 0.20);
  }

  #addPaymentModal .addpay-header{
    padding: 1.2rem 1.4rem;
    background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 55%, #2563eb 100%);
    color: #fff;
  }

  #addPaymentModal .addpay-icon-wrap{
    width: 48px;
    height: 48px;
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255,255,255,.14);
    border: 1px solid rgba(255,255,255,.18);
    font-size: 1.15rem;
  }

  #addPaymentModal .modal-title{
    font-weight: 700;
    font-size: 1.2rem;
  }

  #addPaymentModal .addpay-subtitle{
    font-size: .88rem;
    opacity: .86;
  }

  #addPaymentModal .addpay-close{
    filter: invert(1) grayscale(100%) brightness(200%);
    opacity: .9;
  }

  #addPaymentModal .addpay-body{
    padding: 1.35rem;
  }

  #addPaymentModal .addpay-footer{
    padding: 1rem 1.35rem 1.35rem;
    background: #f8fafc;
  }

  #addPaymentModal .addpay-card{
    background: #ffffff;
    border: 1px solid #e7edf5;
    border-radius: 18px;
    box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06);
    overflow: hidden;
  }

  #addPaymentModal .addpay-card-head{
    padding: 1rem 1.1rem;
    border-bottom: 1px solid #eef2f7;
    background: linear-gradient(to bottom, #ffffff, #fbfdff);
  }

  #addPaymentModal .addpay-card-head h6{
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    color: #0f172a;
  }

  #addPaymentModal .addpay-card-head p{
    margin: 0;
    font-size: .84rem;
    color: #64748b;
  }

  #addPaymentModal .addpay-card-body{
    padding: 1.1rem;
  }

  #addPaymentModal .addpay-summary-table-wrap{
    border: 1px solid #e9eef5;
    border-radius: 14px;
    overflow: hidden;
  }

  #addPaymentModal .addpay-summary-table{
    margin: 0;
    min-width: unset !important;
  }

  #addPaymentModal .addpay-summary-table thead th{
    background: #f8fafc;
    color: #475569;
    font-size: .84rem;
    font-weight: 700;
    border-bottom: 1px solid #e9eef5;
    padding: .9rem .85rem;
  }

  #addPaymentModal .addpay-summary-table tbody td{
    padding: .9rem .85rem;
    border-bottom: 1px solid #eef2f7;
    color: #0f172a;
    vertical-align: middle;
  }

  #addPaymentModal .addpay-summary-table tbody tr:last-child td{
    border-bottom: 0;
  }

  #addPaymentModal .addpay-summary-table .row-soft td{
    background: #f8fafc;
  }

  #addPaymentModal .addpay-summary-table .row-highlight td{
    background: #eff6ff;
    color: #1e3a8a;
  }

  #addPaymentModal .addpay-label{
    font-weight: 700;
    font-size: .92rem;
    color: #334155;
    margin-bottom: .5rem;
  }

  #addPaymentModal .addpay-input{
    min-height: 46px;
    border-radius: 12px;
    border: 1px solid #dbe4ee;
    box-shadow: none;
    font-size: .95rem;
  }

  #addPaymentModal textarea.addpay-input{
    min-height: 96px;
    resize: vertical;
  }

  #addPaymentModal .addpay-input:focus{
    border-color: #3b82f6;
    box-shadow: 0 0 0 .22rem rgba(59,130,246,.12);
  }

  #addPaymentModal .addpay-currency{
    max-width: 110px;
  }

  #addPaymentModal .addpay-amount-group .addpay-input{
    border-radius: 12px 0 0 12px;
  }

  #addPaymentModal .addpay-amount-group input.addpay-input{
    border-radius: 0;
  }

  #addPaymentModal .addpay-add-btn{
    min-width: 54px;
    border-radius: 0 12px 12px 0;
    border: 0;
    background: linear-gradient(135deg, #16a34a 0%, #22c55e 100%);
    color: #fff;
    font-weight: 700;
  }

  #addPaymentModal .addpay-add-btn:hover{
    color: #fff;
    filter: brightness(.97);
  }

  #addPaymentModal .addpay-alert{
    background: #ecfeff;
    border: 1px solid #bae6fd;
    color: #0c4a6e;
    border-radius: 14px;
    padding: .95rem 1rem;
    font-size: .9rem;
    line-height: 1.55;
  }

  #addPaymentModal .addpay-items-box{
    border: 1px solid #e7edf5;
    border-radius: 16px;
    overflow: hidden;
    background: #fff;
  }

  #addPaymentModal .addpay-items-table thead th{
    background: #f8fafc;
    color: #475569;
    font-size: .82rem;
    font-weight: 700;
    border-bottom: 1px solid #e9eef5;
    padding: .85rem .7rem;
  }

  #addPaymentModal .addpay-items-table tbody td{
    padding: .8rem .7rem;
    border-bottom: 1px solid #eef2f7;
  }

  #addPaymentModal .addpay-items-table tfoot td{
    background: #f8fafc;
    border-top: 1px solid #e9eef5;
    padding: .85rem .7rem;
  }

  #addPaymentModal .addpay-btn-secondary{
    background: #64748b;
    color: #fff;
    border: 0;
    border-radius: 12px;
    padding: .6rem 1.05rem;
    font-weight: 600;
  }

  #addPaymentModal .addpay-btn-secondary:hover{
    background: #475569;
    color: #fff;
  }

  #addPaymentModal .addpay-btn-primary{
    background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
    color: #fff;
    border: 0;
    border-radius: 12px;
    padding: .6rem 1.15rem;
    font-weight: 700;
    box-shadow: 0 10px 24px rgba(37,99,235,.18);
  }

  #addPaymentModal .addpay-btn-primary:hover{
    color: #fff;
    filter: brightness(.98);
  }

  #addPaymentModal .table{
    margin-bottom: 0;
  }

  #addPaymentModal .table>:not(caption)>*>*{
    box-shadow: none !important;
  }

  @media (max-width: 991.98px){
    #addPaymentModal .modal-dialog{
      max-width: calc(100% - 1rem);
      margin: .5rem auto;
    }

    #addPaymentModal .addpay-body{
      padding: 1rem;
    }
  }

  @media (max-width: 767.98px){
    #addPaymentModal .addpay-header{
      padding: 1rem;
    }

    #addPaymentModal .addpay-footer{
      padding: 1rem;
    }

    #addPaymentModal .addpay-card-body,
    #addPaymentModal .addpay-card-head{
      padding: .95rem;
    }
  }
</style>

<!-- Customize Installment Plan Modal (unique ID) -->
<div class="modal fade" id="<?= $customModalId ?>" tabindex="-1" aria-hidden="true"
     data-bs-backdrop="static" data-bs-keyboard="false" aria-labelledby="<?= $customModalId ?>Label">
  <div class="modal-dialog modal-lg">
    <form class="modal-content" id="customPlanForm-<?= $SID ?>">
      <div class="modal-header">
        <h5 class="modal-title" id="<?= $customModalId ?>Label">Customize Installment Plan</h5>
        <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">X</button>

      </div>
      <div class="modal-body">
        <input type="hidden" name="student_id" value="<?= (int)$SID ?>">
        <div class="table-responsive border rounded">
          <table class="table table-sm align-middle mb-0" id="customPlanTable-<?= $SID ?>">
            <thead class="table-light">
              <tr>
                <th style="width:75px">#</th>
                <th>Course Fee (LKR)</th>
                <th>Reg Fee (LKR)</th>
                <th>Cert Fee (USD)</th>
                <th style="min-width:140px">Due Date</th>
                <th style="width:44px"></th>
              </tr>
            </thead>
            <tbody></tbody>
          </table>
        </div>
        <div class="mt-2 text-end">
          <button type="button" class="btn btn-sm btn-outline-secondary" id="addRowBtn-<?= $SID ?>">+ row</button>
        </div>
        <div class="mt-3">
          <label class="form-label">Reason for requesting a custom installment plan? <span class="text-danger">*</span></label>
          <textarea name="reason" class="form-control" rows="3" required></textarea>
          <div class="form-text">Please provide a valid reason</div>
        </div>
        <div class="alert alert-secondary mt-3">The student was clearly informed that the requested plan must be authorized by the Branch Manager. If authorization fails, they revert to the pre-defined plan.</div>
        <div class="form-check mb-2">
          <input class="form-check-input" type="checkbox" id="ackAuth-<?= $SID ?>" required>
          <label class="form-check-label" for="ackAuth-<?= $SID ?>">I confirm I informed the student about the above.</label>
        </div>
      </div>
      <div class="modal-footer">
        <button class="btn btn-secondary" data-bs-dismiss="modal" type="button">Close</button>
        <button class="btn btn-primary" type="submit">Send for Authorization</button>
      </div>
    </form>
  </div>
</div>

<?php
$sv_ref_no = trim((string)($student['reference_no'] ?? $student['ref_no'] ?? $student['reference_number'] ?? ''));
$sv_first  = trim((string)($student['first_name'] ?? ''));
$sv_last   = trim((string)($student['last_name'] ?? ''));
$sv_cert   = trim((string)($student['name_on_certificate'] ?? $student['certificate_name'] ?? (($sv_first . ' ' . $sv_last))));
?>

<!-- =========================
     STUDENT DATA VERIFICATION MODAL
========================= -->
<div class="modal fade" id="studentVerifyModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered modal-lg">
    <div class="modal-content sv-modal">
      <div class="sv-topbar"></div>

      <div class="modal-header sv-header border-0">
        <div class="sv-title-wrap">
          <span class="sv-badge">EDEN CAMPUS</span>
          <h5 class="modal-title sv-title" id="studentVerifyModalLabel">Student Data Verification</h5>
          <p class="sv-subtitle mb-0">Confirm student details before sending OTP verification.</p>
        </div>
        <button type="button" class="btn-close sv-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>

      <form id="studentVerifyForm" autocomplete="off">
        <div class="modal-body sv-body">
          <input type="hidden" name="student_id" id="verify_student_id" value="<?= (int)$student_id ?>">

          <div class="sv-section-card">
            <div class="sv-section-head">
              <div class="sv-section-icon"><i class="bi bi-person-vcard"></i></div>
              <div>
                <div class="sv-section-title">Basic Information</div>
                <div class="sv-section-sub">Please review and confirm the student's personal details.</div>
              </div>
            </div>

            <div class="row g-3 mt-1">
              <div class="col-md-4">
                <label class="sv-label">Reference No <span class="text-danger">*</span></label>
                <div class="sv-input-wrap">
                  <span class="sv-input-icon"><i class="bi bi-hash"></i></span>
                  <input type="text"
                         class="form-control sv-input"
                         name="student_ref_no"
                         id="verify_student_ref_no"
                         value="<?= h($sv_ref_no) ?>"
                         readonly>
                </div>
              </div>

              <div class="col-md-4">
                <label class="sv-label">First Name <span class="text-danger">*</span></label>
                <div class="sv-input-wrap">
                  <span class="sv-input-icon"><i class="bi bi-person"></i></span>
                  <input type="text"
                         class="form-control sv-input"
                         name="first_name"
                         id="verify_first_name"
                         value="<?= h($sv_first) ?>"
                         required>
                </div>
              </div>

              <div class="col-md-4">
                <label class="sv-label">Last Name <span class="text-danger">*</span></label>
                <div class="sv-input-wrap">
                  <span class="sv-input-icon"><i class="bi bi-person-badge"></i></span>
                  <input type="text"
                         class="form-control sv-input"
                         name="last_name"
                         id="verify_last_name"
                         value="<?= h($sv_last) ?>"
                         required>
                </div>
              </div>

              <div class="col-12">
                <label class="sv-label">Name on the Certificate <span class="text-danger">*</span></label>
                <div class="sv-input-wrap">
                  <span class="sv-input-icon"><i class="bi bi-award"></i></span>
                  <input type="text"
                         class="form-control sv-input"
                         name="certificate_name"
                         id="verify_certificate_name"
                         value="<?= h($sv_cert) ?>"
                         required>
                </div>
              </div>
            </div>
          </div>

          <div class="sv-note-card mt-3">
            <div class="sv-note-icon"><i class="bi bi-shield-lock"></i></div>
            <div>
              <div class="sv-note-title">Verification Notice</div>
              <div class="sv-note-text">
                Please ensure the student has access to the registered mobile number. An OTP will be sent after saving these details.
              </div>
            </div>
          </div>

          <div id="verifyResult" class="mt-3"></div>
        </div>

        <div class="modal-footer sv-footer border-0">
          <button type="button" class="btn sv-btn-light" data-bs-dismiss="modal">Close</button>
          <button type="submit" class="btn sv-btn-primary" id="btnSaveVerify">
            <span class="verify-btn-text">Save &amp; Verify</span>
          </button>
        </div>
      </form>
    </div>
  </div>
</div>

<!-- =========================
     OTP MODAL
========================= -->
<div class="modal fade" id="otpModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">

      <div class="modal-header">
        <div class="w-100 otp3-top">
          <div class="otp3-badge">
            <i class="bi bi-shield-check"></i>
            Secure Verification
          </div>
          <div class="otp3-icon-wrap">
            <div class="otp3-icon">
              <i class="bi bi-shield-lock"></i>
            </div>
          </div>
          <h5 class="otp3-title">Enter OTP Code</h5>
          <div class="otp3-subtitle">
            Enter the 6-digit verification code to complete student data verification.
          </div>
        </div>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>

      <form id="otpForm" autocomplete="off">
        <div class="modal-body otp3-body">
          <div class="otp3-card">
            <input type="hidden" name="student_id" id="otp_student_id" value="<?= (int)$student_id ?>">

            <label class="otp3-label" for="otpInput">6-digit code</label>

            <input
              type="text"
              class="form-control otp3-input"
              name="otp"
              id="otpInput"
              maxlength="6"
              inputmode="numeric"
              pattern="[0-9]{6}"
              placeholder="000000"
              required
            >

            <div class="otp3-help">
              SMS service is currently unavailable. Use the OTP shown below.
            </div>

            <div id="devOtpHint" class="otp3-devhint d-none"></div>
            <div id="otpResult" class="mt-3"></div>
          </div>
        </div>

        <div class="modal-footer otp3-footer">
          <button type="button" class="btn otp3-btn-light" data-bs-dismiss="modal">Close</button>
          <button type="submit" class="btn otp3-btn-primary" id="btnOtp">Verify OTP</button>
        </div>
      </form>

    </div>
  </div>
</div>
<!-- Toast container -->
<div id="toastContainer" class="toast-container position-fixed top-0 end-0 p-3" aria-live="polite" aria-atomic="true"></div>

<!-- libs (load BEFORE our inline scripts) -->
<?php if (!$is_embed): ?>
  <!-- Only include libs in full page mode -->
  <script src="/assets/js/jquery.min.js"></script>
  <script src="/assets/js/bootstrap.bundle.min.js"></script>
</body>
</html>
<?php endif; ?>
<script>
(function () {
  const parent = document.getElementById('actionModal');
  const btn    = document.getElementById('btnCustomizePlan');
  if (!parent || !btn) return;

  function ensureAtBody(id) {
    const sel  = id.replace(/^#/, '');
    const list = document.querySelectorAll('#' + CSS.escape(sel));
    list.forEach((el, i) => { if (i > 0) el.remove(); });
    const el = list[0] || document.getElementById(sel);
    if (el && el.parentElement !== document.body) document.body.appendChild(el);
    return el;
  }

  btn.addEventListener('click', (e) => {
    e.preventDefault();
    e.stopPropagation();

    const id = btn.getAttribute('data-target');
    const el = ensureAtBody(id);
    if (!el) return;

    // keep parent open and body locked
    document.body.classList.add('modal-open');
    parent.classList.add('show');
    parent.style.display = 'block';

    const child = bootstrap.Modal.getOrCreateInstance(el, { backdrop: 'static', keyboard: false });
    child.show();

    el.addEventListener('hidden.bs.modal', () => {
      // when child closes, keep parent visible and clean up backdrops
      if (!document.querySelector('.modal.show')) {
        document.querySelectorAll('.modal-backdrop').forEach(b => b.remove());
        document.body.classList.add('modal-open');
        parent.classList.add('show');
        parent.style.display = 'block';
      }
    }, { once: true });
  });

  // absolutely ignore hash changes that aren’t real tab panes
  window.addEventListener('hashchange', () => {
    const h = location.hash;
    const pane = h && document.querySelector(h);
    if (!pane || !pane.classList.contains('tab-pane')) {
      history.replaceState(null, '', location.pathname + location.search);
    }
  });
})();
</script>
<script>
// === Globals from PHP ===
window.EC_IS_ADMIN   = <?= $is_admin ? 'true' : 'false' ?>;
window.EC_STUDENT_ID = <?= (int)$student_id ?>;

// Messages used by toasts / responses
window.MESSAGES = window.MESSAGES || {
  approval_sent: 'Approval sent to admin',
  plan_applied:  'Customize Installment Plan added',
  error:         'Something went wrong'
};

// Ensure toast root under <body>
(() => {
  const wrap = document.getElementById('toastContainer');
  if (wrap && wrap.parentElement !== document.body) document.body.appendChild(wrap);
})();

// Keep Student Overview modal static/open unless explicitly closed
(() => {
  const modal = document.getElementById('actionModal');
  if (!modal) return;
  const inst = bootstrap.Modal.getOrCreateInstance(modal, { backdrop: 'static', keyboard: false });
  if (!modal.classList.contains('show')) inst.show();
  window.__blockActionModalHide = false;
  modal.addEventListener('hide.bs.modal', (ev) => { if (window.__blockActionModalHide) ev.preventDefault(); });
})();

// Little helpers
function showToast(msg, type='success') {
  const id = 't' + String(Date.now());
  const html = `
    <div id="${id}" class="toast align-items-center text-bg-${type} border-0 mb-2" role="alert" aria-live="assertive" aria-atomic="true">
      <div class="d-flex">
        <div class="toast-body">${msg}</div>
        <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
      </div>
    </div>`;
  const wrap = document.getElementById('toastContainer');
  wrap.insertAdjacentHTML('beforeend', html);
  new bootstrap.Toast(document.getElementById(id), { delay: 3500 }).show();
}

function setActiveTab(selector) { try { localStorage.setItem(`EC_TAB_${window.EC_STUDENT_ID}`, selector); } catch(e) {} }
// save selected tab
document.addEventListener('shown.bs.tab', function (e) {
  const studentId = window.EC_STUDENT_ID || '0';
  const target = e.target?.getAttribute('data-bs-target') || e.target?.getAttribute('href');
  if (target) localStorage.setItem(`EC_TAB_${studentId}`, target);
});

// restore selected tab (treat hash as tab only if it points to .tab-pane)
function restoreActiveTab() {
  const studentId = window.EC_STUDENT_ID || '0';
  const saved = localStorage.getItem(`EC_TAB_${studentId}`);
  const hash  = window.location.hash;

  const paneEl = hash ? document.querySelector(hash) : null;
  const isTabPane = !!(paneEl && paneEl.classList.contains('tab-pane'));

  const target = isTabPane ? hash : saved;
  if (!target) return;

  const trigger = document.querySelector(
    `[data-bs-toggle="tab"][data-bs-target="${target}"], a[data-bs-toggle="tab"][href="${target}"]`
  );
  if (trigger) new bootstrap.Tab(trigger).show();
}

document.addEventListener('DOMContentLoaded', restoreActiveTab);


// Persist active tab
window.addEventListener('pageshow', restoreActiveTab);
document.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('[data-bs-toggle="tab"]').forEach(el => {
    el.addEventListener('shown.bs.tab', (e) => {
      const sel = e.target.getAttribute('data-bs-target') || e.target.getAttribute('href');
      if (sel) setActiveTab(sel);
    });
  });
  restoreActiveTab();
});

// Re-open #actionModal after a full refresh if it was open
(() => {
  const KEY = 'EC_ACTION_OPEN';
  const modal = document.getElementById('actionModal');
  if (!modal) return;
  modal.addEventListener('show.bs.modal', () => { try { localStorage.setItem(KEY, '1'); } catch {} });
  modal.addEventListener('hidden.bs.modal', () => { try { localStorage.removeItem(KEY); } catch {} });
  document.addEventListener('DOMContentLoaded', () => {
    try {
      if (localStorage.getItem(KEY) === '1') {
        const inst = bootstrap.Modal.getOrCreateInstance(modal, { backdrop: 'static', keyboard: false });
        inst.show();
        const tab = localStorage.getItem(`EC_TAB_${window.EC_STUDENT_ID}`) || '#overview';
        setTimeout(() => reloadStudentTabs(window.EC_STUDENT_ID, tab), 40);
      }
    } catch {}
  });
})();

// Utility to programmatically open the modal
window.openStudentOverview = function (studentId, tab = '#overview') {
  const modal = document.getElementById('actionModal');
  window.EC_STUDENT_ID = studentId;
  try { localStorage.setItem('EC_ACTION_OPEN', '1'); } catch {}
  const inst = bootstrap.Modal.getOrCreateInstance(modal, { backdrop: 'static', keyboard: false });
  inst.show();
  reloadStudentTabs(studentId, tab);
};

// Single source of truth: reload the modal body (prevents refresh issues)
window.__loadedSrcScripts = window.__loadedSrcScripts || new Set();
window.reloadStudentTabs = async function reloadStudentTabs(studentId, afterTab) {
  const parentModalEl = document.getElementById('actionModal');
  const $body = $('#actionModal .modal-body');

  const inst = bootstrap.Modal.getOrCreateInstance(parentModalEl, { backdrop: 'static', keyboard: false });
  if (!parentModalEl.classList.contains('show')) inst.show();
  document.body.classList.add('modal-open');

  // clear tooltips & show spinner
  document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => bootstrap.Tooltip.getInstance(el)?.dispose());
  $('.tooltip').remove();
  $body.html('<div class="text-center py-5"><div class="spinner-border text-info"></div></div>');

  try {
const courseId = (document.getElementById('actionModal')?.dataset.courseId) || '';
const html = await $.get('/edenrms/pages/student_action_tabs.php', {
  id: studentId,
  course_id: courseId || undefined,
  modal: 1,
  _: Date.now()
});



    // extract inline & src scripts
    const $tmp = $('<div>').html(html);
    $tmp.find('#actionModal').remove(); 
    const scripts = [];
    $tmp.find('script').each(function () {
      scripts.push({ src: this.getAttribute('src'), type: this.getAttribute('type'), text: this.textContent || '' });
      $(this).remove();
    });

    // inject fresh markup
    $body.html($tmp.html());

// replay scripts
scripts.forEach(s => {
  if (s.src) {
    if (window.__loadedSrcScripts.has(s.src)) return;
    const tag = document.createElement('script');
    if (s.type) tag.type = s.type;
    tag.src = s.src;
    (document.body || document.head).appendChild(tag);
    window.__loadedSrcScripts.add(s.src);
    return;
  }

  const tag = document.createElement('script');
  if (s.type) tag.type = s.type;

  let code = s.text || '';
  code = code.replace(/\b(?:var|let|const)\s+MESSAGES\s*=/g, 'window.MESSAGES = window.MESSAGES ||');
  code = code.replace(/\b(?:var|let|const)\s+refreshParentAfterCustomPlan\s*=/g, 'window.refreshParentAfterCustomPlan =');

  tag.textContent = code; // ✅ use textContent
  (document.body || document.head).appendChild(tag);

  // ✅ remove safely
  if (tag.parentNode) tag.parentNode.removeChild(tag);
});


    // Move unique child modals to <body> and dedupe
    ['addPaymentModal', `customPlanModal-${studentId}`, 'verifyModal', 'otpModal'].forEach(id => {
  const arr  = Array.from(document.querySelectorAll('#' + CSS.escape(id)));
  const keep = arr.find(el => el.dataset && el.dataset.wired === '1') || arr[0];
  arr.forEach(el => { if (el !== keep) el.remove(); });
  if (keep && keep.parentElement !== document.body) document.body.appendChild(keep);
});


    // Show requested tab (selector or '#payments')
    if (afterTab) {
      let linkEl = null;
      if (afterTab instanceof HTMLElement) linkEl = afterTab;
      else if (typeof afterTab === 'string') {
        const looksSelector = /[\s\[>]/.test(afterTab) && !/^#\w+$/i.test(afterTab);
        if (looksSelector) linkEl = document.querySelector(afterTab);
        if (!linkEl) {
          const hash = afterTab.startsWith('#') ? afterTab : ('#' + afterTab);
          linkEl = document.querySelector(
            `#actionModal .nav-link[data-bs-target="${hash}"], #actionModal .nav-link[href="${hash}"]`
          ) || document.querySelector(hash);
        }
      }
      if (linkEl) new bootstrap.Tab(linkEl).show();
    }

    // Re-enable tooltips
    document.querySelectorAll('#actionModal [data-bs-toggle="tooltip"]').forEach(el => new bootstrap.Tooltip(el));

    // keep body locked
    document.body.classList.add('modal-open');
  } catch (err) {
    $body.html(
      '<div class="p-3 text-danger">Failed to reload. ' +
      (err.responseText || err.statusText || err.message || 'Unknown error') +
      '</div>'
    );
  }
};

// stacked z-index for nested modals (bind once)
if (!window.__modalStackBound) {
  window.__modalStackBound = true;
  $(document)
    .on('show.bs.modal', '.modal', function () {
      const z = 1055 + (10 * $('.modal:visible').length);
      $(this).css('z-index', z);
      setTimeout(() => {
        $('.modal-backdrop').not('.modal-stack')
          .css('z-index', z - 1)
          .addClass('modal-stack');
      }, 0);
    })
    .on('hidden.bs.modal', '.modal', function () {
      if ($('.modal:visible').length) $('body').addClass('modal-open');
    });
}

// Tooltips init for anything inside the Student modal
function initTooltips() {
  document.querySelectorAll('#actionModal [data-bs-toggle="tooltip"]').forEach(el => new bootstrap.Tooltip(el));
}
document.addEventListener('DOMContentLoaded', initTooltips);

// A couple of small utilities used elsewhere
function openReceipt(paymentId) {
  window.open(
    'edenrms/pages/receipt.php?payment_id=' + encodeURIComponent(paymentId) + '&auto=1',
    'receipt','width=900,height=600'
  );
}
</script>
<script>
(function(){
  const openBtn     = document.getElementById('goVerify');
  const verifyModal = document.getElementById('studentVerifyModal');
  const otpModal    = document.getElementById('otpModal');
  const verifyForm  = document.getElementById('studentVerifyForm');
  const otpForm     = document.getElementById('otpForm');
  const verifyBox   = document.getElementById('verifyResult');
  const otpBox      = document.getElementById('otpResult');
  const devOtpHint  = document.getElementById('devOtpHint');

  if (openBtn && verifyModal) {
    openBtn.addEventListener('click', function(e){
      e.preventDefault();
      if (verifyBox) verifyBox.innerHTML = '';
      bootstrap.Modal.getOrCreateInstance(verifyModal).show();
    });
  }

  if (verifyForm) {
    verifyForm.addEventListener('submit', async function(e){
      e.preventDefault();

      const btn = document.getElementById('btnSaveVerify');
      const btnText = btn ? btn.querySelector('.verify-btn-text') : null;

      if (verifyBox) verifyBox.innerHTML = '';
      if (btn) btn.disabled = true;
      if (btnText) btnText.textContent = 'Saving...';

      try {
        const fd = new FormData(verifyForm);

        const sid = String(fd.get('student_id') || '').trim();
        const otpSid = document.getElementById('otp_student_id');
        if (otpSid) otpSid.value = sid;

        const res = await fetch('/edenrms/ajax/complete_verification.php', {
          method: 'POST',
          body: fd,
          credentials: 'include'
        });

        const txt = await res.text();
        let j;
        try {
          j = JSON.parse(txt);
        } catch {
          throw new Error('Non-JSON from /edenrms/ajax/complete_verification.php: ' + txt.slice(0, 200));
        }

        if (!res.ok || j.ok === false) {
          throw new Error(j.message || 'Verification failed');
        }

        if (devOtpHint) {
          if (j.otp) {
            devOtpHint.textContent = 'OTP: ' + j.otp;
            devOtpHint.classList.remove('d-none');
          } else {
            devOtpHint.textContent = '';
            devOtpHint.classList.add('d-none');
          }
        }

        bootstrap.Modal.getInstance(verifyModal)?.hide();

        setTimeout(() => {
          bootstrap.Modal.getOrCreateInstance(otpModal).show();
          const otpInput = document.getElementById('otpInput');
          if (otpInput) {
            otpInput.value = '';
            otpInput.focus();
          }
        }, 220);

      } catch (err) {
        if (verifyBox) {
          verifyBox.innerHTML = `<div class="verify-alert verify-alert-danger">${err.message || 'Verification failed.'}</div>`;
        } else {
          alert(err.message || 'Verification failed.');
        }
      } finally {
        if (btn) btn.disabled = false;
        if (btnText) btnText.textContent = 'Save & Verify';
      }
    });
  }

  if (otpForm) {
    otpForm.addEventListener('submit', async function(e){
      e.preventDefault();

      const btn = document.getElementById('btnOtp');
      const otpInput = document.getElementById('otpInput');

      if (otpBox) otpBox.innerHTML = '';
      if (btn) {
        btn.disabled = true;
        btn.textContent = 'Verifying...';
      }

      try {
        const fd2 = new FormData(otpForm);
        const sid = String(fd2.get('student_id') || '').trim();
        const otp = String(fd2.get('otp') || '').trim();

        if (!sid || !otp) {
          throw new Error('Student ID and OTP are required');
        }

        const res2 = await fetch('/edenrms/ajax/verify_otp.php', {
          method: 'POST',
          body: fd2,
          credentials: 'include'
        });

        const txt2 = await res2.text();
        let j2;
        try {
          j2 = JSON.parse(txt2);
        } catch {
          throw new Error('Non-JSON from /edenrms/ajax/verify_otp.php: ' + txt2.slice(0, 200));
        }

        if (!res2.ok || j2.ok === false) {
          throw new Error(j2.message || 'Invalid OTP');
        }

        if (otpBox) {
          otpBox.innerHTML = `<div class="otp-alert otp-alert-success">Verification completed successfully.</div>`;
        }

        setTimeout(() => {
          bootstrap.Modal.getInstance(otpModal)?.hide();

          if (typeof reloadStudentTabs === 'function') {
            reloadStudentTabs(<?= (int)$student_id ?>, '#overview');
          } else {
            location.reload();
          }
        }, 500);

      } catch (err) {
        if (otpBox) {
          otpBox.innerHTML = `<div class="otp-alert otp-alert-danger">${err.message || 'OTP verification failed.'}</div>`;
        } else {
          alert(err.message || 'OTP verification failed.');
        }

        if (otpInput) otpInput.focus();
      } finally {
        if (btn) {
          btn.disabled = false;
          btn.textContent = 'Verify OTP';
        }
      }
    });
  }
})();




// Open Add Payment modal and seed hidden fields
window.openAddPayment = function (studentId, planId, courseId) {
  const modal = document.getElementById('addPaymentModal');
  const apStudent = document.getElementById('ap_student_id');
  const apPlan    = document.getElementById('ap_plan_id');
  const apCourse  = document.getElementById('ap_course_id');

  if (apStudent) apStudent.value = parseInt(studentId || 0, 10) || 0;
  if (apPlan)    apPlan.value    = parseInt(planId || 0, 10) || 0;

  let resolvedCourseId = parseInt(courseId || 0, 10) || 0;

  if (!resolvedCourseId) {
    resolvedCourseId =
      parseInt(document.getElementById('actionModal')?.dataset.courseId || 0, 10) ||
      parseInt(modal?.dataset.courseId || 0, 10) ||
      0;
  }

  if (apCourse) apCourse.value = resolvedCourseId;

  if (modal) {
    modal.dataset.studentId = String(parseInt(studentId || 0, 10) || 0);
    modal.dataset.planId    = String(parseInt(planId || 0, 10) || 0);
    modal.dataset.courseId  = String(resolvedCourseId);
    bootstrap.Modal.getOrCreateInstance(modal).show();
  }
};

// Simple receipt popup
window.openReceipt = function (paymentId) {
  window.open(
    'edenrms/pages/receipt.php?payment_id=' + encodeURIComponent(paymentId) + '&auto=1',
    'receipt',
    'width=900,height=600'
  );
};
</script>

<!-- 1) Add Payment modal logic (robust, balance-aware) -->
<!-- 1) Add Payment modal logic (robust, balance-aware) -->
<script>
(() => {
  const modalEl = document.getElementById('addPaymentModal');
  if (!modalEl || modalEl.dataset.apWired === '1') return;
  modalEl.dataset.apWired = '1';

  const formEl      = modalEl.querySelector('#addPaymentForm');
  const feeTypeEl   = modalEl.querySelector('#ap_fee_type');
  const currencyEl  = modalEl.querySelector('#ap_currency');
  const amountEl    = modalEl.querySelector('#ap_amount');
  const methodEl    = modalEl.querySelector('#ap_method');
  const refEl       = modalEl.querySelector('#ap_ref');
  const notesEl     = modalEl.querySelector('#ap_notes');
  const addBtnEl    = modalEl.querySelector('#ap_add_btn');
  const saveBtnEl   = modalEl.querySelector('#ap_save_btn');
  const itemsWrapEl = modalEl.querySelector('#ap_items_wrap');
  const itemsTbody  = modalEl.querySelector('#ap_items_table tbody');
  const totalLkrEl  = modalEl.querySelector('#ap_total_lkr');
  const totalUsdEl  = modalEl.querySelector('#ap_total_usd');
  const hintEl      = modalEl.querySelector('#ap_hint');

  const studentIdEl = modalEl.querySelector('#ap_student_id');
  const planIdEl    = modalEl.querySelector('#ap_plan_id');
  const courseIdEl  = modalEl.querySelector('#ap_course_id');

  let items = [];

  function num(v) {
    const x = parseFloat(String(v ?? '').replace(/[^0-9.\-]/g, ''));
    return Number.isFinite(x) ? x : 0;
  }

  function fmt(v) {
    return num(v).toFixed(2);
  }

  function esc(str) {
    return String(str ?? '')
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#039;');
  }

  function getBalances() {
  return {
    courseLkr: num(modalEl.dataset.courseBalance || 0),
    regLkr:    num(modalEl.dataset.regBalance || 0),
    ukaUsd:    num(modalEl.dataset.ukawardsBalance || 0),
    extraLkr:  num(modalEl.dataset.extraBalance || 0)
  };
}

function currentItemTotals() {
  let courseLkr = 0;
  let regLkr    = 0;
  let ukaUsd    = 0;
  let extraLkr  = 0;

  items.forEach(it => {
    const type = String(it.type || '').trim().toLowerCase();
    const ccy  = String(it.currency || 'LKR').trim().toUpperCase();
    const amt  = num(it.amount);

    if ((type === 'course fee' || type === 'course_fee') && ccy === 'LKR') {
      courseLkr += amt;
    } else if ((type === 'registration fee' || type === 'registration_fee' || type === 'reg fee') && ccy === 'LKR') {
      regLkr += amt;
    } else if ((type === 'uk awards fee' || type === 'uk_awards_fee' || type === 'certificate fee' || type === 'cert fee') && ccy === 'USD') {
      ukaUsd += amt;
    } else if ((type === 'extra fee(s)' || type === 'extra fees' || type === 'extra fee' || type === 'extra_fee') && ccy === 'LKR') {
      extraLkr += amt;
    }
  });

  return { courseLkr, regLkr, ukaUsd, extraLkr };
}

function getRemainingFor(type, currency) {
  const balances = getBalances();
  const used = currentItemTotals();

  const t = String(type || '').trim().toLowerCase();
  const c = String(currency || 'LKR').trim().toUpperCase();

  if ((t === 'course fee' || t === 'course_fee') && c === 'LKR') {
    return Math.max(0, balances.courseLkr - used.courseLkr);
  }

  if ((t === 'registration fee' || t === 'registration_fee' || t === 'reg fee') && c === 'LKR') {
    return Math.max(0, balances.regLkr - used.regLkr);
  }

  if ((t === 'uk awards fee' || t === 'uk_awards_fee' || t === 'certificate fee' || t === 'cert fee') && c === 'USD') {
    return Math.max(0, balances.ukaUsd - used.ukaUsd);
  }

  if ((t === 'extra fee(s)' || t === 'extra fees' || t === 'extra fee' || t === 'extra_fee') && c === 'LKR') {
    return Math.max(0, balances.extraLkr - used.extraLkr);
  }

  return 0;
}

  function autoFillAmount() {
    if (!feeTypeEl || !currencyEl || !amountEl) return;
    const rem = getRemainingFor(feeTypeEl.value, currencyEl.value);
    amountEl.value = fmt(rem);
  }

  function renderItems() {
    if (!itemsWrapEl || !itemsTbody || !totalLkrEl || !totalUsdEl) return;

    if (!items.length) {
      itemsWrapEl.classList.add('d-none');
      itemsTbody.innerHTML = '';
      totalLkrEl.textContent = '0.00';
      totalUsdEl.textContent = '0.00';
      return;
    }

    itemsWrapEl.classList.remove('d-none');

    itemsTbody.innerHTML = items.map((it, i) => `
      <tr>
        <td class="text-start fw-semibold">${esc(it.type)}</td>
        <td>${esc(it.currency)}</td>
        <td class="text-end">${fmt(it.amount)}</td>
        <td>${esc(it.method)}</td>
        <td class="text-center">
          <button type="button" class="btn btn-sm btn-outline-danger ap-remove-item" data-index="${i}">
            <i class="bi bi-trash"></i>
          </button>
        </td>
      </tr>
    `).join('');

    const totalLkr = items.reduce((s, it) => s + (String(it.currency).toUpperCase() === 'LKR' ? num(it.amount) : 0), 0);
    const totalUsd = items.reduce((s, it) => s + (String(it.currency).toUpperCase() === 'USD' ? num(it.amount) : 0), 0);

    totalLkrEl.textContent = fmt(totalLkr);
    totalUsdEl.textContent = fmt(totalUsd);

    itemsTbody.querySelectorAll('.ap-remove-item').forEach(btn => {
      btn.addEventListener('click', () => {
        const idx = parseInt(btn.dataset.index || '-1', 10);
        if (idx >= 0) {
          items.splice(idx, 1);
          renderItems();
          autoFillAmount();
        }
      });
    });
  }

  function addItem() {
    const feeType  = String(feeTypeEl?.value || '').trim();
    const currency = String(currencyEl?.value || 'LKR').trim().toUpperCase();
    const amount   = num(amountEl?.value || 0);
    const method   = String(methodEl?.value || 'Cash').trim();

    if (!feeType) {
      alert('Please select Fee Type.');
      feeTypeEl?.focus();
      return;
    }

    if (amount <= 0) {
      alert('Please enter a valid Amount.');
      amountEl?.focus();
      return;
    }

    const remaining = getRemainingFor(feeType, currency);
    if (amount > remaining + 0.009) {
      alert('Entered amount is greater than outstanding balance for selected fee type.');
      amountEl?.focus();
      return;
    }

    items.push({
      type: feeType,
      currency: currency,
      amount: amount,
      method: method
    });

    renderItems();

    if (feeTypeEl) feeTypeEl.value = '';
    if (currencyEl) currencyEl.value = 'LKR';
    if (amountEl) amountEl.value = '0.00';
  }

  function resetFormState() {
    items = [];
    renderItems();

    if (feeTypeEl) feeTypeEl.value = '';
    if (currencyEl) currencyEl.value = 'LKR';
    if (amountEl) amountEl.value = '0.00';
    if (methodEl) methodEl.value = 'Cash';
    if (refEl) refEl.value = '';
    if (notesEl) notesEl.value = '';
    if (hintEl) hintEl.textContent = '';
  }

  feeTypeEl?.addEventListener('change', autoFillAmount);
  currencyEl?.addEventListener('change', autoFillAmount);

  addBtnEl?.addEventListener('click', function(e) {
    e.preventDefault();
    addItem();
  });

  amountEl?.addEventListener('keydown', function(e) {
    if (e.key === 'Enter') {
      e.preventDefault();
      addItem();
    }
  });

  modalEl.addEventListener('shown.bs.modal', function() {
    renderItems();
    autoFillAmount();
  });

  modalEl.addEventListener('hidden.bs.modal', function() {
    resetFormState();
  });

  formEl?.addEventListener('submit', async function(e) {
    e.preventDefault();

    if (!items.length) {
      alert('Please add at least one payment item using the + button.');
      return;
    }

    const studentId = parseInt(studentIdEl?.value || 0, 10) || 0;
    let planId      = parseInt(planIdEl?.value || 0, 10) || 0;
    let courseId    = parseInt(courseIdEl?.value || 0, 10) || 0;

    if (!courseId) {
      courseId = parseInt(document.getElementById('actionModal')?.dataset.courseId || 0, 10) || 0;
      if (courseIdEl) courseIdEl.value = String(courseId || 0);
    }

    if (!studentId) {
      alert('student_id missing');
      return;
    }

    if (!courseId) {
      alert('course_id missing');
      return;
    }

    const totalLkr = items.reduce((s, it) => s + (String(it.currency).toUpperCase() === 'LKR' ? num(it.amount) : 0), 0);
    const totalUsd = items.reduce((s, it) => s + (String(it.currency).toUpperCase() === 'USD' ? num(it.amount) : 0), 0);
    const lastMethod = items[items.length - 1]?.method || 'Cash';
    const feeType = items.length === 1 ? items[0].type : 'Mixed';

    const fd = new FormData();
    fd.append('student_id', String(studentId));
    fd.append('plan_id', String(planId));
    fd.append('course_id', String(courseId));
    fd.append('amount', fmt(totalLkr));
    fd.append('usd_amount', fmt(totalUsd));
    fd.append('currency', 'LKR');
    fd.append('fee_type', feeType);
    fd.append('payment_method', lastMethod);
    fd.append('reference_no', refEl?.value || '');
    fd.append('notes', notesEl?.value || '');
    fd.append('items_json', JSON.stringify({
      items: items,
      total_lkr: fmt(totalLkr),
      total_usd: fmt(totalUsd)
    }));

    try {
      if (saveBtnEl) {
        saveBtnEl.disabled = true;
        saveBtnEl.innerHTML = '<i class="bi bi-hourglass-split me-1"></i> Saving...';
      }
      if (hintEl) hintEl.textContent = 'Saving payment...';

      const res = await fetch('/edenrms/pages/submit_payment.php', {
        method: 'POST',
        body: fd,
        credentials: 'include'
      });

      const text = await res.text();
      let json = null;

      try { json = JSON.parse(text); } catch (_) {}

      if (!res.ok) {
        throw new Error((json && (json.message || json.error)) || text || 'Server error');
      }

      if (json && json.ok === false) {
        throw new Error(json.message || 'Failed to save payment');
      }

      alert((json && (json.message || json.success)) || 'Payment saved successfully.');

      const modal = bootstrap.Modal.getInstance(modalEl);
      if (modal) modal.hide();

      if (typeof reloadStudentTabs === 'function') {
        reloadStudentTabs(studentId, '#payments');
      }
    } catch (err) {
      console.error(err);
      const msg = err?.message || 'Unknown error';
      alert('Failed to save payment: ' + msg);
      if (hintEl) hintEl.textContent = 'Failed to save payment: ' + msg;
    } finally {
      if (saveBtnEl) {
        saveBtnEl.disabled = false;
        saveBtnEl.innerHTML = '<i class="bi bi-save2 me-1"></i> Save Payment';
      }
    }
  });
})();
</script>

<!-- 2) Live totals + Discount/Extra + Checklist -->
<script>
let discLkr  = parseFloat(<?= json_encode($discount_lkr) ?>) || 0;
let extraLkr = parseFloat(<?= json_encode($extra_fee_lkr) ?>) || 0; 

function recalcTotals() {
  const course = parseFloat(<?= json_encode($course_fee_lkr) ?>);
  const reg    = parseFloat(<?= json_encode($reg_fee_lkr) ?>);
  const certU  = parseFloat(<?= json_encode($cert_fee_usd) ?>);
  const paid   = parseFloat(<?= json_encode($already_paid_lkr) ?>);
  const paidUsd= parseFloat(<?= json_encode($paid_uka) ?>);
  const late   = parseFloat(<?= json_encode($late_charges) ?>);

  const subLkr   = course + reg;
  const totalLkr = Math.max(0, subLkr - discLkr + late + extraLkr);
  const outLkr   = Math.max(0, totalLkr - paid);
  const outUsd   = Math.max(0, certU - paidUsd);

  document.getElementById('pp_sub_lkr').textContent   = subLkr.toFixed(2) + ' LKR';
  document.getElementById('pp_total_lkr').textContent = totalLkr.toFixed(2) + ' LKR';
  document.getElementById('pp_out_lkr').textContent   = outLkr.toFixed(2) + ' LKR';
  document.getElementById('pp_sub_usd').textContent   = certU.toFixed(2) + ' USD';
  document.getElementById('pp_total_usd').textContent = certU.toFixed(2) + ' USD';
  document.getElementById('pp_out_usd').textContent   = outUsd.toFixed(2) + ' USD';

  const rowDisc  = document.getElementById('row_discount');
  if (rowDisc) {
    if (discLkr > 0) { rowDisc.classList.remove('d-none'); document.getElementById('pp_disc_lkr').textContent = discLkr.toFixed(2) + ' LKR'; }
    else rowDisc.classList.add('d-none');
  }

  const rowExtra = document.getElementById('row_extra');
  if (rowExtra) {
    if (extraLkr > 0) { rowExtra.classList.remove('d-none'); document.getElementById('pp_extra_lkr').textContent = extraLkr.toFixed(2) + ' LKR'; }
    else rowExtra.classList.add('d-none');
  }
}
recalcTotals();

async function postAndRefresh(url, label, fd) {
  try {
    const res  = await fetch(url, { method:'POST', body: fd, credentials:'include' });
    const txt  = await res.text();
    let j;
    try { j = JSON.parse(txt); } catch { j = { ok: res.ok, message: (txt||'').trim() }; }

    if (!res.ok || j.ok === false) {
      alert(`${label} failed: ${j.message || 'Server error'}`);
      return;
    }

    alert(j.message || `${label} saved.`);
    const sid = window.EC_STUDENT_ID || '';
    if (sid) {
      reloadStudentTabs(sid, '#payments');
      setTimeout(() => {
        document.querySelector('#actionModal #installmentPlanBlock')
          ?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }, 350);
    }
  } catch (e) {
    alert(`${label} failed: ${e.message || 'Network error'}`);
  }
}


function openAddDiscount() {
  const v = prompt('Discount amount in LKR (whole plan):', '');
  if (v === null) return;
  const amt = Math.max(0, parseFloat(v) || 0);
  if (amt <= 0) return alert('Please enter a positive amount.');
  const reason = prompt('Reason for discount (required):', '') || '';
  const fd = new FormData();
  fd.append('student_id', String(window.EC_STUDENT_ID || <?= (int)$student_id ?>));
  fd.append('amount', amt.toFixed(2));
  fd.append('reason', reason);
  postAndRefresh('/edenrms/pages/submit_discount.php', 'Discount', fd);
}

function openAddExtra() {
  const v = prompt('Extra fee amount in LKR (whole plan):', '');
  if (v === null) return;
  const amt = Math.max(0, parseFloat(v) || 0);
  if (amt <= 0) return alert('Please enter a positive amount.');
  const reason = prompt('Reason for extra fee (required):', '') || '';
  const fd = new FormData();
  fd.append('student_id', String(window.EC_STUDENT_ID || <?= (int)$student_id ?>));
  fd.append('amount', amt.toFixed(2));
  fd.append('reason', reason);
  postAndRefresh('/edenrms/pages/submit_extra_fee.php', 'Extra fee', fd);
}

/* Checklist save */
async function parseJSONorThrow(res, url){ const text = await res.text(); try { return JSON.parse(text); } catch { throw new Error(`Non-JSON from ${url}: `+text.slice(0,200)); } }
function saveChecklist(studentId) {
  const items = {
    c1: document.getElementById('c1')?.checked || false,
    c2: document.getElementById('c2')?.checked || false,
    c3: document.getElementById('c3')?.checked || false,
    c4: document.getElementById('c4')?.checked || false,
    c5: document.getElementById('c5')?.checked || false,
    c6: document.getElementById('c6')?.checked || false
  };
  const fd = new FormData();
  fd.append('student_id', studentId);
  fd.append('items', JSON.stringify(items));

  const url = '/edenrms/ajax/save_checklist.php';
  fetch(url, { method: 'POST', body: fd })
    .then(res => parseJSONorThrow(res, url))
    .then(j => {
      const data = j.data ?? j;
      let completed = Number(data.completed ?? 0);
      let total     = Number(data.total ?? 0);
      if (!total) {
        const boxes = [items.c1, items.c2, items.c3, items.c4, items.c5, items.c6];
        total = boxes.length;
        completed = boxes.filter(Boolean).length;
      }
      alert(`Checklist saved (${completed}/${total} completed).`);
      reloadStudentTabs(<?= (int)$student_id ?>);
    })
    .catch(err => alert('Failed to save: ' + (err.message || 'Unknown error')));
}
</script>


<script>
// Toggle show/hide for the LMS password (eye button)
function wireLmsPasswordToggle() {
  const btn    = document.getElementById('btnTogglePw');
  const masked = document.getElementById('lmsPasswordMasked');
  const plain  = document.getElementById('lmsPasswordPlain');

  if (!btn || !masked || !plain) return;

  btn.addEventListener('click', () => {
    const isHidden = plain.classList.contains('d-none');

    // if currently hidden -> show plain, hide bullets
    plain.classList.toggle('d-none', !isHidden);
    masked.classList.toggle('d-none', isHidden);

    const icon = btn.querySelector('i');
    if (icon) {
      icon.classList.toggle('bi-eye', !isHidden);
      icon.classList.toggle('bi-eye-slash', isHidden);
    }
  });
}

// Used after AJAX reset to rebuild the cell with bullets + eye + new plain password.
// If plain is null/empty, we still show bullets but nothing to reveal.
function renderLmsPasswordCell(plain) {
  const cell = document.getElementById('lmsPassword');
  if (!cell) return;

  if (plain) {
    cell.innerHTML = `
      <span id="lmsPasswordMasked">••••••••</span>
      <code id="lmsPasswordPlain" class="d-none"></code>
      <button type="button"
              class="btn btn-sm btn-outline-secondary ms-1"
              id="btnTogglePw">
        <i class="bi bi-eye"></i>
      </button>
    `;
    cell.querySelector('#lmsPasswordPlain').textContent = plain;
  } else {
    // No plain available, just show fixed bullets
    cell.innerHTML = `
      <span id="lmsPasswordMasked">••••••••</span>
      <code id="lmsPasswordPlain" class="d-none"></code>
      <button type="button"
              class="btn btn-sm btn-outline-secondary ms-1"
              id="btnTogglePw">
        <i class="bi bi-eye"></i>
      </button>
    `;
  }

  wireLmsPasswordToggle();
}

// Wire eye-button for the initial HTML that PHP rendered
document.addEventListener('DOMContentLoaded', wireLmsPasswordToggle);
</script>

<!-- 4) LMS: Create/Activate/Reset + explicit status dropdown -->
<script>
(() => {
  const studentId = <?= (int)$student_id ?>;
  const btnCreate = document.getElementById('btnLmsAssign');
  const btnReset  = document.getElementById('btnLmsReset');
  const statusSel = document.getElementById('lmsStatusSelect');
  const badge     = document.getElementById('lmsStatusBadge');

  // 3-way status map: value -> {label, badgeClass}
  const STATUS_MAP = {
    1: { label: 'Active',    cls: 'bg-success'   },
    0: { label: 'Inactive',  cls: 'bg-secondary'  },
    2: { label: 'Suspended', cls: 'bg-danger'     },
  };

  function updateStatusUI(val) {
    const s = STATUS_MAP[val] ?? STATUS_MAP[1];
    if (badge) {
      badge.className = 'badge ' + s.cls;
      badge.textContent = s.label;
    }
    if (statusSel) statusSel.value = String(val);
    if (btnCreate) {
      // Show Deactivate only when Active; otherwise offer Create/Activate
      btnCreate.innerHTML = (val === 1)
        ? '<i class="bi bi-dash-circle"></i> Deactivate'
        : '<i class="bi bi-plus-lg"></i> Create / Activate';
    }
  }

  async function callCreateOrToggle(target = null, override = false) {
    const fd = new FormData();
    fd.append('student_id', String(studentId));
    fd.append('id',         String(studentId));
    if (target !== null) fd.append('target', String(target));
    if (override) fd.append('override', '1');

    const res = await fetch(
      '/edenrms/pages/student_action_tabs.php?do=create_or_toggle_lms',
      { method: 'POST', body: fd }
    );

    const j = await res.json().catch(() => ({ ok: false, message: 'Non-JSON' }));

    if (!res.ok || j.ok === false) {
      if (j.needs_override && !override) {
        if (confirm('Outstanding dues exist. Activate anyway?')) {
          return callCreateOrToggle(target, true);
        }
      }
      alert('Failed: ' + (j.message || 'Server error'));
      // Revert the dropdown to its previous value if we know it
      if (statusSel && target !== null) {
        // re-read badge to figure out previous
        const prevLabel = badge?.textContent?.trim() || 'Active';
        const prevVal = Object.entries(STATUS_MAP)
          .find(([, v]) => v.label === prevLabel)?.[0] ?? '1';
        statusSel.value = prevVal;
      }
      return;
    }

    // Update UI with server-confirmed value
    const newVal  = parseInt(j.active, 10);
    const safeVal = [0, 1, 2].includes(newVal) ? newVal : 1;
    updateStatusUI(safeVal);

    if (j.just_created && j.email) {
      const emailCell = document.getElementById('lmsEmail');
      if (emailCell) emailCell.textContent = j.email;
    }

    if (j.overdue && newVal === 1) {
      alert('Activated with outstanding dues (manual override).');
    }
  }

  // Create / Activate button (toggle between active and inactive)
  btnCreate?.addEventListener('click', () => callCreateOrToggle(null, false));

  // Status dropdown — now supports 0 / 1 / 2
  statusSel?.addEventListener('change', () => {
    const target = parseInt(statusSel.value, 10);
    callCreateOrToggle(isNaN(target) ? null : target, false);
  });

  // Reset Password button
  btnReset?.addEventListener('click', async () => {
    const fd = new FormData();
    fd.append('student_id', String(studentId));
    fd.append('id',         String(studentId));

    const res = await fetch(
      '/edenrms/pages/student_action_tabs.php?do=reset_academic',
      { method: 'POST', body: fd }
    );

    const j = await res.json().catch(() => ({ ok: false, message: 'Non-JSON' }));
    if (!res.ok || j.ok === false) {
      alert('Failed to reset: ' + (j.message || 'Server error'));
      return;
    }

    renderLmsPasswordCell(j.pw || null);
    const resetCell = document.getElementById('lmsResets');
if (resetCell && typeof j.reset_count !== 'undefined') {
  resetCell.textContent = String(j.reset_count);
}

    if (window.showToast) {
      showToast('LMS password has been reset successfully.', 'success');
    } else {
      alert('LMS password has been reset successfully.');
    }

    const sid = window.EC_STUDENT_ID || studentId;
    if (typeof reloadStudentTabs === 'function') {
      reloadStudentTabs(sid, '#other');
    }
  });
})();
</script>


<!-- 5) Customize Installment Plan (unique IDs) -->
<script>
(() => {
    const modalId  = "<?= $customModalId ?>";
  const modalEl  = document.getElementById(modalId);
  if (!modalEl || modalEl.dataset.wired === '1') return;  // bind at most once per DOM node
  modalEl.dataset.wired = '1';

  const parentModal = document.getElementById('actionModal');
  const formEl      = document.getElementById('customPlanForm-<?= $SID ?>');
  const tbody       = document.querySelector('#customPlanTable-<?= $SID ?> tbody');
  const addRowBtn   = document.getElementById('addRowBtn-<?= $SID ?>');
  const ackEl       = document.getElementById('ackAuth-<?= $SID ?>');
  if (!modalEl || !formEl || !tbody) return;

  const ensureAtBody = () => {
    const existing = document.getElementById(modalId);
    if (existing && existing !== modalEl) existing.remove();       // drop stale duplicate
    if (modalEl.parentElement !== document.body) document.body.appendChild(modalEl);
  };

  function addCustomRow(no = '', course = '0', reg = '0', cert = '0', date = '') {
    const tr = document.createElement('tr');
    tr.innerHTML = `
      <td><input type="number" class="form-control form-control-sm" name="no[]" value="${no}"></td>
      <td><input type="number" step="0.01" class="form-control form-control-sm" name="course_lkr[]" value="${course}"></td>
      <td><input type="number" step="0.01" class="form-control form-control-sm" name="reg_lkr[]" value="${reg}"></td>
      <td><input type="number" step="0.01" class="form-control form-control-sm" name="cert_usd[]" value="${cert}"></td>
      <td><input type="date" class="form-control form-control-sm" name="due_date[]" value="${date}"></td>
      <td><button type="button" class="btn btn-sm btn-outline-danger remove-row">×</button></td>`;
    tbody.appendChild(tr);
  }

function prefillFromCurrentTable() {
  tbody.innerHTML = '';
  const srcBody = document.querySelector('#actionModal #installmentTbody');
  if (!srcBody) { addCustomRow(); return; }

  srcBody.querySelectorAll('tr.ip-row[data-no]').forEach(tr => {
    addCustomRow(
      tr.dataset.no || '',
      tr.dataset.courseRaw || tr.dataset.course || '0',
      tr.dataset.reg || '0',
      tr.dataset.cert || '0',
      tr.dataset.date || ''
    );
  });

  if (!tbody.querySelector('tr')) addCustomRow();
}




  modalEl.addEventListener('show.bs.modal', () => {
    ensureAtBody();
    prefillFromCurrentTable();
    if (parentModal) {
      document.body.classList.add('modal-open');
      parentModal.classList.add('show');
      parentModal.style.display = 'block';
      parentModal.removeAttribute('aria-hidden');
    }
  });

  modalEl.addEventListener('click', (e) => {
    const btn = e.target.closest('.remove-row');
    if (!btn) return;
    btn.closest('tr')?.remove();
    if (!tbody.querySelector('tr')) addCustomRow();
  });

  addRowBtn?.addEventListener('click', () => addCustomRow());

  formEl.addEventListener('submit', (e) => {
    e.preventDefault();
    if (!ackEl?.checked) return alert('Please tick the confirmation checkbox.');

    const fd = new FormData(formEl);
    fetch('/edenrms/pages/submit_custom_plan.php', { method: 'POST', body: fd, credentials: 'include' })
      .then(r => r.text())
      .then(raw => {
        let ok=false, msg='', code='';
        try {
          const j = JSON.parse(raw);
          ok = !!(j.ok || j.success || j.approved || j.applied);
          if (j.applied === true || j.approved === true) code = 'plan_applied';
          else if (j.pending === true)                   code = 'approval_sent';
          else                                           code = (j.message_code || '').toLowerCase();
          msg = j.message || '';
        } catch {
          ok   = /ok|applied|approved|submitted/i.test(raw);
          code = /applied|approved/i.test(raw) ? 'plan_applied' : 'approval_sent';
          msg  = raw;
        }
        if (code === 'applied' || code === 'approved')  code = 'plan_applied';
        if (code === 'submitted' || code === 'pending') code = 'approval_sent';
        const finalMsg = (window.MESSAGES && window.MESSAGES[code]) || msg ||
                         (code === 'plan_applied' ? 'Customize Installment Plan added' : 'Approval sent to admin');

        (window.toastr ? toastr.success(finalMsg) : alert(finalMsg));

        document.activeElement?.blur();
        bootstrap.Modal.getInstance(modalEl)?.hide();

        const studentId = formEl.querySelector('[name="student_id"]')?.value || '';
        reloadStudentTabs(studentId, '#payments');


        setTimeout(() => {
          document.querySelector('#actionModal #installmentPlanBlock')
            ?.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }, 350);
      })
      .catch(err => (window.toastr ? toastr.error(err.message || 'Failed') : alert(err.message || 'Failed')));
  });
})();

</script>


<script>
document.addEventListener('click', function (e) {
  const btn = e.target.closest('#btnTogglePw');
  if (!btn) return;

  const masked = document.getElementById('lmsPasswordMasked');
  const plain  = document.getElementById('lmsPasswordPlain');
  if (!masked || !plain) return;

  const isShowing = !plain.classList.contains('d-none');

  if (isShowing) {
    plain.classList.add('d-none');
    masked.classList.remove('d-none');
    btn.innerHTML = '<i class="bi bi-eye"></i>';
  } else {
    plain.classList.remove('d-none');
    masked.classList.add('d-none');
    btn.innerHTML = '<i class="bi bi-eye-slash"></i>';
  }
});
</script>
<script>
// === Keep #actionModal open while a child modal (Customize Plan) is shown ===
(function () {
  var parent = document.getElementById('actionModal');
  if (!parent) return;

  // Track how many nested modals are open
  var nestedOpen = 0;

  // Never allow the parent to hide while a child is open
  parent.addEventListener('hide.bs.modal', function (ev) {
    if (nestedOpen > 0) ev.preventDefault();
  });

  // Helper: ensure a modal node lives under <body> and dedupe if multiple exist
  function ensureAtBody(id) {
    var sel = id.replace(/^#/, '');
    var list = document.querySelectorAll('#' + CSS.escape(sel));
    list.forEach(function (el, i) { if (i > 0) el.remove(); });
    var el = list[0];
    if (el && el.parentElement !== document.body) document.body.appendChild(el);
    return el || document.getElementById(sel);
  }

  // Intercept clicks that open the custom plan modal (via <a href="#..."> or data-bs-target)
  document.addEventListener('click', function (e) {
    var trigger = e.target.closest(
  '[data-bs-target^="#customPlanModal-"],' +
  'a[href^="#customPlanModal-"],' +
  '#btnCustomizePlan[data-target^="#customPlanModal-"]'
);
    if (!trigger) return;

    // Stop URL hash changes (which can flip your tab to match the new hash)
    if (trigger.tagName === 'A') e.preventDefault();
    e.stopPropagation();

    var id = trigger.getAttribute('data-bs-target') ||
         trigger.getAttribute('href') ||
         trigger.getAttribute('data-target');
    var el = ensureAtBody(id);
    if (!el) return;

    // Show the child modal; keep parent visually open/locked
    var child = bootstrap.Modal.getOrCreateInstance(el, { backdrop: 'static', keyboard: false });
    document.body.classList.add('modal-open');
    parent.classList.add('show');
    parent.style.display = 'block';
    child.show();
  }, true);

  // When ANY modal shows/hides, keep stacking/z-index and modal-open state correct
  document.addEventListener('show.bs.modal', function (ev) {
    var el = ev.target;
    // Count only our custom-plan modals
    if (el.id && /^customPlanModal-/.test(el.id)) {
      nestedOpen++;
      // z-index stacking (safe even if you also open Add Payment etc.)
      var z = 1055 + (10 * document.querySelectorAll('.modal.show').length);
      el.style.zIndex = z;
      setTimeout(function () {
        document.querySelectorAll('.modal-backdrop')
          .forEach(function (bd) { if (!bd.classList.contains('modal-stack')) { bd.style.zIndex = z - 1; bd.classList.add('modal-stack'); } });
      }, 0);
      // Make sure body stays locked and parent remains "open"
      document.body.classList.add('modal-open');
      parent.classList.add('show');
      parent.style.display = 'block';
    }
  });

  document.addEventListener('hidden.bs.modal', function (ev) {
    var el = ev.target;
    if (el.id && /^customPlanModal-/.test(el.id)) {
      nestedOpen = Math.max(0, nestedOpen - 1);
      // If another child is still open, keep body locked
      if (nestedOpen > 0 || document.querySelector('.modal.show')) {
        document.body.classList.add('modal-open');
      } else {
        // Otherwise, restore body to a clean state, but keep parent visible
        document.querySelectorAll('.modal-backdrop').forEach(function (b) { b.remove(); });
        document.body.classList.remove('modal-open');
        parent.classList.add('show');
        parent.style.display = 'block';
      }
    }
  });

  // SAFER backdrop cleanup: only when NO modals are visible
  document.addEventListener('hidden.bs.modal', function () {
    if (!document.querySelector('.modal.show')) {
      document.querySelectorAll('.modal-backdrop').forEach(function (b) { b.remove(); });
      document.body.classList.remove('modal-open');
      document.body.style.removeProperty('padding-right');
    }
  });
})();
</script>
<script>
function renderLmsPasswordCell(plainPassword) {
  const cell = document.getElementById('lmsPassword');
  if (!cell) return;

  // If we have a plain password (academic_plain_password column exists)
  if (plainPassword && String(plainPassword).trim() !== '') {
    cell.innerHTML = `
      <span id="lmsPasswordMasked">••••••••</span>
      <code id="lmsPasswordPlain" class="d-none"></code>
      <button type="button"
              class="btn btn-sm btn-outline-secondary ms-1"
              id="btnTogglePw">
        <i class="bi bi-eye"></i>
      </button>
    `;

    // Fill the plain text safely
    const plainEl = cell.querySelector('#lmsPasswordPlain');
    if (plainEl) plainEl.textContent = plainPassword;
  } else {
    // No plain available → only show hashed indicator
    cell.innerHTML = `<span class="text-muted">•••••••• (hashed)</span>`;
  }
}
</script>
