<?php

/**
 * 1) GET COMPETITION DETAILS + NUMBER OF JUDGES
 */
function getCompetitionDetails($conn, $competitionCode) {
	$competitionQuery = "SELECT id, name FROM competitions WHERE code = ?";
	$competitionStmt = $conn->prepare($competitionQuery);
	if (!$competitionStmt) {
		die("Prepare failed: " . $conn->error);
	}
	$competitionStmt->bind_param("s", $competitionCode);
	$competitionStmt->execute();
	$competitionResult = $competitionStmt->get_result();
	$competition = $competitionResult->fetch_assoc();
	$competitionId   = $competition['id']   ?? null;
	$competitionName = $competition['name'] ?? null;

	$settingsQuery = "SELECT judges AS number_of_judges FROM settings WHERE competition_code = ? LIMIT 1";
	$settingsStmt = $conn->prepare($settingsQuery);
	if (!$settingsStmt) {
		die("Prepare failed: " . $conn->error);
	}
	$settingsStmt->bind_param("s", $competitionCode);
	$settingsStmt->execute();
	$settingsResult    = $settingsStmt->get_result();
	$numberOfJudges    = $settingsResult->fetch_assoc()['number_of_judges'] ?? 0;

	return [
		"competitionId"   => $competitionId,
		"competitionName" => $competitionName,
		"numberOfJudges"  => $numberOfJudges
	];
}

/**
 * 2) FETCH OFFICIALS
 */
function getOfficials($conn, $competitionId, $eventId, $groupNumber) {
	$officialsQuery = "
		SELECT 
			op.official AS official_id,
			op.judge    AS judge_number,
			o.iwwf_id,
			CONCAT(o.first_name, ' ', o.last_name) AS official_name
		FROM officials_panel op
		JOIN officials o ON op.official = o.id
		WHERE op.competition = ? 
		  AND op.event       = ?
		  AND op.category    = ?
	";
	$officialsStmt = $conn->prepare($officialsQuery);
	if (!$officialsStmt) {
		die("Prepare failed: " . $conn->error);
	}
	$officialsStmt->bind_param("iii", $competitionId, $eventId, $groupNumber);
	$officialsStmt->execute();
	$officialsResult = $officialsStmt->get_result();

	$officials = [];
	while ($officialRow = $officialsResult->fetch_assoc()) {
		$officials[] = [
			"official_id"   => $officialRow['official_id'],
			"judge_number"  => $officialRow['judge_number'],
			"iwwf_id"       => $officialRow['iwwf_id'],
			"official_name" => $officialRow['official_name']
		];
	}
	return $officials;
}

/**
 * 2A) Get a single schedule row (for explicit schedule ID).
 */
function getOneScheduleRow($conn, $scheduleId) {
	$q = "
		SELECT s.id,
			   s.event,
			   e.id,
			   e.event_name AS event_name,
			   s.category,
			   c.name AS category_name,
			   h.name AS heatsystem_name,
			   h.round AS round_number,
			   h.qualify AS qualify_number,
			   (
				   SELECT COUNT(DISTINCT r.group)
				   FROM runs r
				   WHERE r.schedule = s.id
			   ) AS groups_count
		FROM schedule s
		JOIN categories c ON s.category = c.id
		JOIN heatsystem h ON s.heatsystem = h.id
		JOIN events e ON s.event = e.id
		WHERE s.id = ?
		LIMIT 1
	";
	$stmt = $conn->prepare($q);
	if (!$stmt) {
		die("Prepare getOneScheduleRow failed: " . $conn->error);
	}
	$stmt->bind_param("i", $scheduleId);
	$stmt->execute();
	$res = $stmt->get_result();
	return $res->fetch_assoc() ?: null;
}

/**
 * 3) GET RUNS (AND SCORES) FOR A SCHEDULE + GROUP
 */
function getRuns($conn, $competitionId, $scheduleId, $groupNumber, $judgeIwwfId, $public = false) {
// 1) Build $scoreSelect depending on judgeIwwfId:
if ($judgeIwwfId !== null) {
	// Individual score for this official (seat) in the same competition/event/category
	$scoreSelect = "(
		SELECT sc.score
		FROM scores sc
		JOIN officials_panel op2 ON sc.judge = op2.judge
		JOIN officials o3        ON op2.official = o3.id
		WHERE sc.run = r.id
		  AND op2.competition = s.comp
		  AND op2.event       = s.event
		  AND op2.category    = s.category
		  AND o3.iwwf_id      = ?
		LIMIT 1
	) AS individual_score";
} else {
	// Average of all judges' scores
	$scoreSelect = "(
		SELECT AVG(sc.score)
		FROM scores sc
		WHERE sc.run = r.id
	) AS average_score";
}

// 2) Main query: now we JOIN schedule s ON r.schedule = s.id
//    so we have s.comp, s.event, s.category for the subselect correlation
$runsQuery = "
	SELECT 
		r.id           AS run_id,
		r.run          AS run_number,
		CONCAT(a.first_name, ' ', a.last_name) AS athlete_name,
		a.id           AS athlete_id,
		a.year_of_birth,
		a.country,
		a.sponsors,
		a.training_site,
		a.bib,
		a.ranking_place,
		c.name         AS country_name,
		r.status       AS run_status,
		r.timestamp    AS run_time,
		s.event        AS event_id,
		s.category     AS category_id,
		r.`order`,
		{$scoreSelect}
	FROM runs r
	JOIN schedule s ON r.schedule = s.id
	LEFT JOIN athletes  a ON r.athlete = a.id
	LEFT JOIN countries c ON a.country = c.code
	WHERE r.schedule = ?
	  AND r.group    = ?
	ORDER BY r.schedule, r.`group`, r.run, r.`order` ASC";

	$stmt = $conn->prepare($runsQuery);
	if (!$stmt) {
		die("Prepare getRuns failed: " . $conn->error);
	}

	if ($judgeIwwfId !== null) {
		$stmt->bind_param("sii", $judgeIwwfId, $scheduleId, $groupNumber);
	} else {
		$stmt->bind_param("ii", $scheduleId, $groupNumber);
	}

	$stmt->execute();
	$result = $stmt->get_result();

	$mergedRuns    = [];
	$activeAthlete = null;

	while ($run = $result->fetch_assoc()) {
		$athleteId = $run['athlete_id'] ?? null;
		$key = ($athleteId !== null) ? $athleteId : 'no_athlete_run_' . $run['run_id'];

		if (!isset($mergedRuns[$key])) {
			$mergedRuns[$key] = [
				"athlete_name" => $run['athlete_name'] ?? "Unknown Athlete",
				"birthyear"    => $run['year_of_birth'] ?? null,
				"country"      => $run['country']       ?? "UNK",
				"athlete_id"   => $athleteId,
				"sponsors"     => $run['sponsors']      ?? null,
				"homecable"    => $run['training_site'] ?? null,
				"ranking_place"=> $run['ranking_place'] ?? null,
				"bib"          => $run['bib']           ?? null,
				"runs"         => [],
				"best_score"   => null,
			];
		}

		// Decide the displayed score
		$scoreLabel = null;
		if ($public && $run['run_status'] != 1) {
			// If public => hide if not published
			$scoreLabel = null;
		} else {
			if ($run['run_status'] == 2) {
				$scoreLabel = "FRS";
			} elseif ($run['run_status'] == 3) {
				$scoreLabel = "DNS";
			} elseif ($run['run_status'] == 4) {
				$scoreLabel = "DSQ";
			} else {
				$field = $judgeIwwfId ? "individual_score" : "average_score";
				if (isset($run[$field]) && $run[$field] !== null) {
					$scoreLabel = round($run[$field], 2);
				}
			}
		}

		if (is_numeric($scoreLabel) &&
			($mergedRuns[$key]["best_score"] === null || $scoreLabel > $mergedRuns[$key]["best_score"])) {
			$mergedRuns[$key]["best_score"] = $scoreLabel;
		}

		// Collect this run
		$mergedRuns[$key]["runs"][] = [
			"run_id"     => $run['run_id'],
			"run_number" => $run['run_number'],
			"status"     => $run['run_status'],
			"time"       => $run['run_time'] ?? null,
			"score"      => $scoreLabel,
		];

		// If run_status=0 => first such athlete is "activeAthlete"
		if ($run['run_status'] == 0 && $activeAthlete === null) {
			$activeAthlete = [
				"name"         => $run['athlete_name']  ?? "Unknown",
				"sponsors"     => $run['sponsors']      ?? null,
				"birthyear"    => $run['year_of_birth'] ?? null,
				"country"      => $run['country']       ?? "UNK",
				"country_name" => $run['country_name']  ?? $run['country'],
				"homecable"    => $run['training_site'] ?? "No homecable",
				"ranking_place"=> $run['ranking_place'] ?? null,
				"id"           => $athleteId,
				"run_id"       => $run['run_id'],
				"run_number"   => $run['run_number'],
				"bib"          => $run['bib']           ?? null,
			];
		}
	}

	usort($mergedRuns, function($a, $b) {
		$aScore = $a["best_score"] ?? -INF;
		$bScore = $b["best_score"] ?? -INF;
		return $bScore <=> $aScore;
	});

	// Assign placements
	foreach ($mergedRuns as $index => &$athlete) {
		$athlete["placement"] = $index + 1;
		if ($activeAthlete && $athlete["athlete_id"] === $activeAthlete["id"]) {
			$activeAthlete["placement"] = $athlete["placement"];
		}
	}
	unset($athlete);

	return [array_values($mergedRuns), $activeAthlete];
}

/**
 * findMaxTimestampAthlete => who performed last (by timestamp)
 */
function findMaxTimestampAthlete(array $mergedRuns) {
	$maxTime = null;
	$previousAthlete = null;

	foreach ($mergedRuns as $athleteItem) {
		$common = [
			"name"       => $athleteItem["athlete_name"] ?? "Unknown Athlete",
			"birthyear"  => $athleteItem["birthyear"]    ?? null,
			"country"    => $athleteItem["country"]      ?? "UKN",
			"athlete_id" => $athleteItem["athlete_id"]   ?? null,
			"sponsors"   => $athleteItem["sponsors"]     ?? null,
			"homecable"  => $athleteItem["homecable"]    ?? "N/A",
			"placement"  => $athleteItem["placement"]    ?? null,
			"bib"        => $athleteItem["bib"]          ?? null,
		];

		foreach ($athleteItem["runs"] as $oneRun) {
			if (!empty($oneRun["time"])) {
				$runTime = $oneRun["time"];
				if ($maxTime === null || $runTime > $maxTime) {
					$maxTime = $runTime;
					$previousAthlete = array_merge($common, [
						"run_id"     => $oneRun["run_id"],
						"run_number" => $oneRun["run_number"],
						"time"       => $runTime,
						"score"      => $oneRun["score"],
						"status"     => $oneRun["status"],
					]);
				}
			}
		}
	}

	return $previousAthlete;
}

/**
 * Count how many runs are still active (status=0). If zero => all finished
 */
function countActiveRuns($conn, $competitionId) {
	$sql = "
		SELECT COUNT(*) AS active_count
		FROM runs r
		JOIN schedule s ON r.schedule = s.id
		WHERE s.comp = ?
		  AND r.status = 0
	";
	$stmt = $conn->prepare($sql);
	if (!$stmt) {
		die("Prepare countActiveRuns failed: " . $conn->error);
	}
	$stmt->bind_param("i", $competitionId);
	$stmt->execute();
	$res = $stmt->get_result();
	$row = $res->fetch_assoc();
	return (int)($row["active_count"] ?? 0);
}

/** 
 * HELPER #1: getScheduleOrder
 */
function getScheduleOrder(mysqli $conn, int $scheduleId) {
	$sql = "SELECT `order` FROM schedule WHERE id = ? LIMIT 1";
	$stmt = $conn->prepare($sql);
	if (!$stmt) {
		die("Prepare getScheduleOrder failed: " . $conn->error);
	}
	$stmt->bind_param("i", $scheduleId);
	$stmt->execute();
	$res = $stmt->get_result();
	$row = $res->fetch_assoc();
	$stmt->close();

	return $row['order'] ?? null;
}

/** 
 * HELPER #2: findPreviousSchedule => schedule with `order` < currentOrder
 */
function findPreviousSchedule(mysqli $conn, int $competitionId, int $currentOrder) {
	$sql = "
		SELECT id
		FROM schedule
		WHERE comp = ?
		  AND `order` < ?
		ORDER BY `order` DESC
		LIMIT 1
	";
	$stmt = $conn->prepare($sql);
	if (!$stmt) {
		die("Prepare findPreviousSchedule failed: " . $conn->error);
	}
	$stmt->bind_param("ii", $competitionId, $currentOrder);
	$stmt->execute();
	$res = $stmt->get_result();
	$row = $res->fetch_assoc();
	$stmt->close();

	return $row ?: null;
}

/** 
 * HELPER #3: findMaxGroup => the highest group in a given schedule
 */
function findMaxGroup(mysqli $conn, int $scheduleId) {
	$sql = "SELECT MAX(`group`) AS max_group FROM runs WHERE schedule = ?";
	$stmt = $conn->prepare($sql);
	if (!$stmt) {
		die("Prepare findMaxGroup failed: " . $conn->error);
	}
	$stmt->bind_param("i", $scheduleId);
	$stmt->execute();
	$res = $stmt->get_result();
	$row = $res->fetch_assoc();
	$stmt->close();

	return $row['max_group'] ?? null;
}

/**
 * The CORRECT getPreviousGroup => uses custom logic:
 *   1) If currentGroup > 0 => same schedule, group = currentGroup - 1
 *   2) If currentGroup=0 => previous schedule by order, group = MAX(group)
 */
/**
  * The CUSTOM getPreviousGroup: 
  *   1) If currentGroup > 0 => same schedule, group = currentGroup - 1
  *      But if that becomes 0 => also fallback to previous schedule & max group
  *   2) If currentGroup=0 => previous schedule & max group immediately
  */
 function getPreviousGroup(mysqli $conn, int $competitionId, int $currentScheduleId, int $currentGroupNumber) {
	 // 1) Get the current schedule's order
	 $currentOrder = getScheduleOrder($conn, $currentScheduleId);
	 if ($currentOrder === null) {
		 // no such schedule => can't find "previous"
		 return null;
	 }
 
	 // We will determine $prevScheduleId and $prevGroupNumber
	 $prevScheduleId  = null;
	 $prevGroupNumber = null;
 
	 if ($currentGroupNumber > 0) {
		 // Subtract 1
		 $testGroup = $currentGroupNumber - 1;
 
		 if ($testGroup > 0) {
			 // OK => we can just do same schedule, group = testGroup
			 $prevScheduleId  = $currentScheduleId;
			 $prevGroupNumber = $testGroup;
		 } else {
			 // testGroup <= 0 => fallback to the "previous schedule"
			 $prevRow = findPreviousSchedule($conn, $competitionId, $currentOrder);
			 if (!$prevRow) {
				 return null; // no earlier schedule
			 }
			 $prevScheduleId  = (int)$prevRow['id'];
			 $prevGroupNumber = findMaxGroup($conn, $prevScheduleId);
			 if ($prevGroupNumber === null) {
				 return null; // no runs in that schedule
			 }
		 }
 
	 } else {
		 // currentGroupNumber == 0 => jump immediately to previous schedule
		 $prevRow = findPreviousSchedule($conn, $competitionId, $currentOrder);
		 if (!$prevRow) {
			 return null;
		 }
		 $prevScheduleId  = (int)$prevRow['id'];
		 $prevGroupNumber = findMaxGroup($conn, $prevScheduleId);
		 if ($prevGroupNumber === null) {
			 return null;
		 }
	 }
 
	 // Now fetch (prevScheduleId, prevGroupNumber)
	 $sql = "
		 SELECT 
			 s.id AS schedule_id,
			 s.order AS schedule_order,
			 r.group AS group_number,
			 c.id AS category_id,
			 c.name AS category_name,
			 e.id AS event_id,
			 e.event_name,
			 h.name AS heatsystem_name,
			 h.round AS round_number,
			 h.qualify AS qualify_number,
			 (
				 SELECT COUNT(DISTINCT r2.group)
				 FROM runs r2
				 WHERE r2.schedule = s.id
			 ) AS groups_count
		 FROM runs r
		 JOIN schedule s   ON r.schedule = s.id
		 JOIN categories c ON s.category = c.id
		 JOIN heatsystem h ON s.heatsystem = h.id
		 JOIN events e     ON s.event = e.id
		 WHERE s.comp = ?
		   AND s.id   = ?
		   AND r.group = ?
		 GROUP BY s.id, r.group
		 LIMIT 1
	 ";
	 $stmt = $conn->prepare($sql);
	 if (!$stmt) {
		 die("Prepare getPreviousGroup(...) failed: " . $conn->error);
	 }
	 $stmt->bind_param("iii", $competitionId, $prevScheduleId, $prevGroupNumber);
	 $stmt->execute();
	 $res = $stmt->get_result();
	 $info = $res->fetch_assoc() ?: null;
	 $stmt->close();
 
	 if (!$info) {
		 return null;
	 }
 
	 // Also find last_run_timestamp
	 $timeSql = "
		 SELECT MAX(r.timestamp) AS lastRunTime
		 FROM runs r
		 WHERE r.schedule = ?
		   AND r.group    = ?
	 ";
	 $ts = $conn->prepare($timeSql);
	 $ts->bind_param("ii", $info['schedule_id'], $info['group_number']);
	 $ts->execute();
	 $tr = $ts->get_result();
	 $timeRow = $tr->fetch_assoc();
	 $ts->close();
 
	 $info['last_run_timestamp'] = $timeRow['lastRunTime'] ?? null;
	 return $info;
 }

/**
 * Return the very last group from the entire competition (i.e. highest run.id).
 * We'll pick that if the competition is fully done
 */
function getLastGroupOfCompetition($conn, $competitionId) {
	$sql = "
		SELECT 
			r.group AS group_number,
			s.id AS schedule_id,
			c.name AS category_name,
			c.id AS category_id,
			s.event AS event_id,
			e.id,
			e.event_name AS event_name,
			h.name AS heatsystem_name,
			CONCAT(c.name, ' ', h.name) AS group_name,
			h.round AS round_number,
			h.qualify AS qualify_number,
			(
				SELECT COUNT(DISTINCT r2.group)
				FROM runs r2
				WHERE r2.schedule = s.id
			) AS groups_count
		FROM runs r
		INNER JOIN schedule s ON r.schedule = s.id
		INNER JOIN categories c ON s.category = c.id
		INNER JOIN heatsystem h ON s.heatsystem = h.id
		INNER JOIN events e ON s.event = e.id
		WHERE s.comp = ?
		ORDER BY r.id DESC
		LIMIT 1
	";
	$stmt = $conn->prepare($sql);
	if (!$stmt) {
		die("Prepare getLastGroupOfCompetition failed: " . $conn->error);
	}
	$stmt->bind_param("i", $competitionId);
	$stmt->execute();
	$res = $stmt->get_result();
	$info = $res->fetch_assoc() ?: null;
	$stmt->close();

	if (!$info) return null;

	// Also get last_run_timestamp
	$timeQuery = "
		SELECT MAX(r.timestamp) AS lastRunTime
		FROM runs r
		WHERE r.schedule = ?
		  AND r.group    = ?
	";
	$timeStmt = $conn->prepare($timeQuery);
	if (!$timeStmt) {
		die("Prepare (last group time) failed: " . $conn->error);
	}
	$timeStmt->bind_param("ii", $info['schedule_id'], $info['group_number']);
	$timeStmt->execute();
	$timeRes = $timeStmt->get_result();
	$timeRow = $timeRes->fetch_assoc();
	$timeStmt->close();

	$info['last_run_timestamp'] = $timeRow['lastRunTime'] ?? null;
	return $info;
}

/**
 * 4) GET ACTIVE GROUP: returns row or null
 *    We do NOT handle the "all done" fallback here.
 */
function getActiveGroup($conn, $competitionId) {
	$activeGroupQuery = "
	SELECT 
		r.group AS group_number,
		s.id AS schedule_id,
		s.order,
		c.name AS category_name,
		c.id AS category_id,
		s.event AS event_id,
		e.id,
		e.event_name AS event_name,
		h.name AS heatsystem_name,
		CONCAT(c.name, ' ', h.name) AS group_name,
		h.round AS round_number,
		h.qualify AS qualify_number,
		(
			SELECT COUNT(DISTINCT r2.group)
			FROM runs r2
			WHERE r2.schedule = s.id
		) AS groups_count
	FROM runs r
	INNER JOIN schedule s ON r.schedule = s.id
	INNER JOIN categories c ON s.category = c.id
	INNER JOIN heatsystem h ON s.heatsystem = h.id
	INNER JOIN events e ON s.event = e.id
	WHERE s.comp = ?
	  AND r.status = 0
	-- Order by schedule.order, then group, then the run index
	ORDER BY s.order ASC, r.group ASC, r.order ASC
	LIMIT 1
";

	$stmt = $conn->prepare($activeGroupQuery);
	if (!$stmt) {
		die("Prepare getActiveGroup failed: " . $conn->error);
	}
	$stmt->bind_param("i", $competitionId);
	$stmt->execute();
	$res  = $stmt->get_result();
	$info = $res->fetch_assoc() ?: null;
	$stmt->close();

	if (!$info) {
		return null; // means no active group found
	}

	// Also get last_run_timestamp
	$timeQuery = "
		SELECT MAX(r.timestamp) AS lastRunTime
		FROM runs r
		WHERE r.schedule = ?
		  AND r.group    = ?
	";
	$timeStmt = $conn->prepare($timeQuery);
	if (!$timeStmt) {
		die("Prepare getActiveGroup time failed: " . $conn->error);
	}
	$timeStmt->bind_param("ii", $info['schedule_id'], $info['group_number']);
	$timeStmt->execute();
	$timeRes = $timeStmt->get_result();
	$timeRow = $timeRes->fetch_assoc();
	$timeStmt->close();

	$info['last_run_timestamp'] = $timeRow['lastRunTime'] ?? null;
	return $info;
}

/**
 * getAllGroups => for debug or listing
 */
function getAllGroups($conn, $competitionId) {
	$groupsQuery = "
		SELECT DISTINCT 
			r.group AS group_number,
			s.id AS schedule_id,
			c.name AS category_name,
			c.id AS category_id,
			s.event AS event_id,
			e.id,
			e.event_name AS event_name,
			h.name AS heatsystem_name,
			CONCAT(c.name, ' ', h.name) AS group_name,
			h.round AS round_number,
			h.qualify AS qualify_number,
			   (
				   SELECT COUNT(DISTINCT r2.group)
				   FROM runs r2
				   WHERE r2.schedule = s.id
			   ) AS groups_count
		FROM runs r
		INNER JOIN schedule s ON r.schedule = s.id
		INNER JOIN categories c ON s.category = c.id
		INNER JOIN heatsystem h ON s.heatsystem = h.id
		INNER JOIN events e ON s.event = e.id
		WHERE s.comp = ?
		ORDER BY r.group ASC
	";

	$stmt = $conn->prepare($groupsQuery);
	if (!$stmt) {
		die("Prepare getAllGroups failed: " . $conn->error);
	}
	$stmt->bind_param("i", $competitionId);
	$stmt->execute();
	$res = $stmt->get_result();

	$groups = [];
	while ($group = $res->fetch_assoc()) {
		$groups[] = $group;
	}
	return $groups;
}

// ------------------------------------------------------
// 7) getData() - MAIN LOGIC
// ------------------------------------------------------
function getData($conn, $competitionCode, $judgeId = null, $allGroups = false, $public = false, $explicitSchedule = null, $explicitGroup = null) {
	$details = getCompetitionDetails($conn, $competitionCode);
	$competitionId   = $details["competitionId"];
	$competitionName = $details["competitionName"];
	$numberOfJudges  = $details["numberOfJudges"];

	if (!$competitionId) {
		return ["success" => false, "error" => "No competition found with the given competition code."];
	}

	// If explicit schedule + group => skip the entire active-group logic
	if ($explicitSchedule !== null && $explicitGroup !== null) {
		$schRow = getOneScheduleRow($conn, $explicitSchedule);
		if (!$schRow) {
			return ["success" => false, "error" => "No schedule found with ID " . $explicitSchedule];
		}

		$officials = getOfficials($conn, $competitionId, $schRow['event'], $schRow['category']);
		list($mergedRuns, $activeAthlete) = getRuns(
			$conn,
			$competitionId,
			$explicitSchedule,
			$explicitGroup,
			$judgeId,
			$public
		);

		$qualify = $schRow['qualify_number'] / $schRow['groups_count'];
		$response = [
			"success"        => true,
			"active_athlete" => $activeAthlete,
			"active_group"   => [
				"schedule_id"      => $explicitSchedule,
				"event_id"         => $schRow['event'],
				"event_name"       => $schRow['event_name'],
				"competitionName"  => $competitionName,
				"category"         => $schRow['category'],
				"category_name"    => $schRow['category_name'],
				"heatsystem_name"  => $schRow['heatsystem_name'],
				"group_name"       => $schRow['category_name'] . " " . $schRow['heatsystem_name'],
				"round"            => $schRow['round_number'],
				"group"            => $explicitGroup,
				"qualify"          => $qualify,
				"number_of_judges" => $numberOfJudges,
				"officials"        => $officials
			],
			"runs" => array_values($mergedRuns),
		];
		return $response;
	}

	// If allGroups => fetch data for each group
	if ($allGroups) {
		$groups = getAllGroups($conn, $competitionId);
		if (empty($groups)) {
			return ["success" => false, "error" => "No groups found for this competition."];
		}

		$allData = [];
		foreach ($groups as $group) {
			$officials = getOfficials(
				$conn,
				$competitionId,
				$group['event_id'],
				$group['category_id']
			);

			list($mergedRuns, $activeAthlete) = getRuns(
				$conn,
				$competitionId,
				$group['schedule_id'],
				$group['group_number'],
				$judgeId,
				$public
			);

			$qualify = $group['qualify_number'] / $group['groups_count'];
			$allData[] = [
				"active_athlete" => $activeAthlete,
				"active_group"   => [
					"schedule_id"      => $group['schedule_id'],
					"event_id"         => $group['event_id'],
					"event_name"       => $group['event_name'],
					"competitionName"  => $competitionName,
					"category"         => $group['category_id'],
					"category_name"    => $group['category_name'],
					"heatsystem_name"  => $group['heatsystem_name'],
					"group_name"       => $group['group_name'],
					"round"            => $group['round_number'],
					"group"            => $group['group_number'],
					"qualify"          => $qualify,
					"number_of_judges" => $numberOfJudges,
					"officials"        => $officials
				],
				"runs" => array_values($mergedRuns),
			];
		}

		return ["success" => true, "groups" => $allData];
	} else {
		// Single active group scenario
		$activeGroup = getActiveGroup($conn, $competitionId);

		// If no active group => check if everything is done => pick last group
		if (!$activeGroup) {
			$activeCount = countActiveRuns($conn, $competitionId);
			if ($activeCount === 0) {
				// means all runs are done => pick last group as the fallback
				$lastGroup = getLastGroupOfCompetition($conn, $competitionId);
				if (!$lastGroup) {
					return ["success" => false, "error" => "No runs exist at all in this competition."];
				}
				// Treat lastGroup as if it is the "activeGroup"
				$activeGroup = $lastGroup;
			} else {
				// Edge case => no runs found as active, but not fully done => error
				return ["success" => false, "error" => "Could not find an active group, but competition not fully done."];
			}
		}

		/** 
		 * Now we do the new "previous group" logic with getPreviousGroup(...).
		 * We pass the *current* schedule + group.
		 */
		$previousGroup = getPreviousGroup(
			$conn,
			$competitionId,
			$activeGroup['schedule_id'],
			$activeGroup['group_number']
		);

		$officialsActive = getOfficials(
			$conn, 
			$competitionId, 
			$activeGroup['event_id'], 
			$activeGroup['category_id']
		);

		list($mergedRunsActive, $activeAthlete) = getRuns(
			$conn,
			$competitionId,
			$activeGroup['schedule_id'],
			$activeGroup['group_number'],
			$judgeId,
			$public
		);

		// If we found a "previous" group => fetch runs, officials, etc.
		$previousGroupData = null;
		if ($previousGroup) {
			$officialsPrev = getOfficials(
				$conn,
				$competitionId,
				$previousGroup['event_id'],
				$previousGroup['category_id']
			);

			list($mergedRunsPrev, $ignore) = getRuns(
				$conn,
				$competitionId,
				$previousGroup['schedule_id'],
				$previousGroup['group_number'],
				$judgeId,
				$public
			);

			$previousAthlete = findMaxTimestampAthlete($mergedRunsPrev);
			$qualify         = $previousGroup['qualify_number'] / $previousGroup['groups_count'];

			$previousGroupData = [
				"previous_athlete" => $previousAthlete,
				"previous_group" => [
					"schedule_id"       => $previousGroup['schedule_id'],
					"event_id"          => $previousGroup['event_id'],
					"event_name"        => $previousGroup['event_name'],
					"category"          => $previousGroup['category_id'],
					"competitionName"   => $competitionName,
					"category_name"     => $previousGroup['category_name'],
					"heatsystem_name"   => $previousGroup['heatsystem_name'],
					"group_name"        => $previousGroup['category_name']." ".$previousGroup['heatsystem_name'],
					"round"             => $previousGroup['round_number'],
					"group"             => $previousGroup['group_number'],
					"qualify"           => $qualify,
					"number_of_judges"  => $numberOfJudges,
					"officials"         => $officialsPrev,
					"last_run_timestamp"=> $previousGroup['last_run_timestamp'],
				],
				"runs" => array_values($mergedRunsPrev),
			];
		}

		// Build final response for the "active" group
		$qualify = $activeGroup['qualify_number'] / $activeGroup['groups_count'];
		$response = [
			"success"        => true,
			"active_athlete" => $activeAthlete,
			"active_group"   => [
				"schedule_id"      => $activeGroup['schedule_id'],
				"event_id"         => $activeGroup['event_id'],
				"event_name"       => $activeGroup['event_name'],
				"competitionName"  => $competitionName,
				"category"         => $activeGroup['category_id'],
				"category_name"    => $activeGroup['category_name'],
				"heatsystem_name"  => $activeGroup['heatsystem_name'],
				"group_name"       => $activeGroup['group_name'],
				"round"            => $activeGroup['round_number'],
				"group"            => $activeGroup['group_number'],
				"qualify"          => $qualify,
				"number_of_judges" => $numberOfJudges,
				"officials"        => $officialsActive,
				"last_run_timestamp" => $activeGroup['last_run_timestamp'] ?? null,
			],
			"runs" => array_values($mergedRunsActive),
		];

		// If we got "previous group" data => include it
		if ($previousGroupData !== null) {
			$response["previous_group_data"] = $previousGroupData;
		}

		return $response;
	}
}

// ------------------------------------------------------
// 8) MAIN ENTRY POINT
// ------------------------------------------------------
if (isset($_GET["competitionCode"])) {
	$competitionCode = $_GET["competitionCode"];
	$judgeId         = isset($_GET["judgeId"])   ? $_GET["judgeId"] : null; 
	$allGroups       = isset($_GET["allGroups"]) && $_GET["allGroups"] === 'true';
	$public          = isset($_GET["public"])    && $_GET["public"]  === 'true';

	$explicitSchedule = isset($_GET["scheduleId"]) ? (int)$_GET["scheduleId"] : null;
	$explicitGroup    = isset($_GET["group"])      ? (int)$_GET["group"]      : null;

	$data = getData(
		$conn, 
		$competitionCode, 
		$judgeId, 
		$allGroups, 
		$public,
		$explicitSchedule,
		$explicitGroup
	);

	$response = [
		"competitionCode" => $competitionCode,
		"data"            => $data
	];

	echo json_encode($response, JSON_PRETTY_PRINT);

} else {
	echo json_encode(["success" => false, "error" => "Parameter 'competitionCode' is missing."]);
}

?>