<?php // api/plan.php
require_once __DIR__ . '/../lib/auth.php';
require_once __DIR__ . '/../lib/acl.php';
require_once __DIR__ . '/../lib/db.php';
require_once __DIR__ . '/../lib/response.php';
require_login();

$program_id = (int)($_GET['program_id'] ?? 0);
if (!$program_id || !user_can_program($program_id)) json_error('Forbidden', 403);

// Parallel testing switch: set to false to only warn (no hard errors on caps)
const STRICT_ENFORCEMENT = false;

$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['items']) || !is_array($input['items'])) json_error('Invalid payload', 400);

// Load program caps and sanity data
$db = db();
$progStmt = $db->prepare('SELECT max_credits_per_semester, max_courses_per_semester FROM programs WHERE id=?');
$progStmt->execute([$program_id]);
$prog = $progStmt->fetch();
if (!$prog) json_error('Program not found', 404);

// Fetch semester ids of this program
$semStmt = $db->prepare('SELECT id FROM semesters WHERE program_id=?');
$semStmt->execute([$program_id]);
$validSemesters = array_column($semStmt->fetchAll(), 'id');
$validSemSet = array_flip($validSemesters);

// Fetch course ids of this program with credits for quick lookup
$courseStmt = $db->prepare('SELECT id, credits FROM courses WHERE program_id=? AND is_active=1');
$courseStmt->execute([$program_id]);
$cmap = [];
foreach ($courseStmt->fetchAll() as $c) { $cmap[(int)$c['id']] = (int)$c['credits']; }

$bySem = [];       // semester_id => [course_id => position]
$dupErrors = [];   // list of duplicate tuples detected in payload
foreach ($input['items'] as $it) {
  $sid = (int)($it['semester_id'] ?? 0);
  $cid = (int)($it['course_id'] ?? 0);
  $pos = (int)($it['position'] ?? 0);

  if (!$sid || !$cid) continue; // ignore unassigned/invalid
  if (!isset($validSemSet[$sid])) { json_error("Semester $sid not in program", 400); }
  if (!isset($cmap[$cid])) { json_error("Course $cid not in program or inactive", 400); }

  if (!isset($bySem[$sid])) $bySem[$sid] = [];
  if (isset($bySem[$sid][$cid])) {
    $dupErrors[] = "Duplicate course $cid in semester $sid";
  } else {
    $bySem[$sid][$cid] = $pos;
  }
}

// Check duplicates in payload
if ($dupErrors) {
  $msg = 'Duplicates detected: ' . implode('; ', $dupErrors);
  json_error($msg, 422);
}

// Compute caps per semester
$capErrors = [];
foreach ($bySem as $sid => $map) {
  $count = count($map);
  $credits = 0;
  foreach ($map as $cid => $_) { $credits += $cmap[$cid] ?? 0; }

  if (!empty($prog['max_courses_per_semester']) && $count > (int)$prog['max_courses_per_semester']) {
    $capErrors[] = "Semester $sid exceeds course cap ({$count}/{$prog['max_courses_per_semester']})";
  }
  if (!empty($prog['max_credits_per_semester']) && $credits > (int)$prog['max_credits_per_semester']) {
    $capErrors[] = "Semester $sid exceeds credit cap ({$credits}/{$prog['max_credits_per_semester']})";
  }
}

if ($capErrors && STRICT_ENFORCEMENT) {
  json_error('Caps validation failed: ' . implode(' | ', $capErrors), 422);
}

// Save inside a transaction: clear and reinsert
try {
  $db->beginTransaction();
  $del = $db->prepare('DELETE FROM plan_courses WHERE program_id=?');
  $del->execute([$program_id]);

  $ins = $db->prepare('INSERT INTO plan_courses (program_id, semester_id, course_id, position) VALUES (?,?,?,?)');
  foreach ($input['items'] as $it) {
    $sid = (int)($it['semester_id'] ?? 0);
    $cid = (int)($it['course_id'] ?? 0);
    $pos = (int)($it['position'] ?? 0);
    if (!$sid || !$cid) continue; // skip unassigned
    $ins->execute([$program_id, $sid, $cid, $pos]);
  }
  $db->commit();

  $resp = ['saved' => count($input['items']), 'capsWarnings' => $capErrors];
  json_ok($resp);
} catch (PDOException $e) {
  $db->rollBack();
  // Likely a UNIQUE violation (semester_id, course_id) or (program_id, course_id)
  json_error('DB error: ' . $e->getMessage(), 500);
}
