<?php

// 1) Include the next_round function from an external file
include_once('functions/next_round.php');
// 2) Include the reversed function from an external file
include_once('functions/reversed.php');  
// 3) Include the finalPlacement function from an external file
include_once('functions/final_placement.php'); 

$method = $_SERVER['REQUEST_METHOD'];

if ($method === 'GET') {
	if (!isset($_GET['runId'])) {
		echo json_encode(["success" => false, "error" => "Missing runId parameter."]);
		exit;
	}

	$runId = intval($_GET['runId']);

	// Fetch scores
	$query = "SELECT judge, score, status FROM scores WHERE run = ?";
	$stmt  = $conn->prepare($query);
	$stmt->bind_param("i", $runId);

	if (!$stmt->execute()) {
		echo json_encode(["success" => false, "error" => "Failed to fetch scores."]);
		exit;
	}

	$result = $stmt->get_result();
	$scores = [];
	$totalScore = 0;
	$judgeCount = 0;

	while ($row = $result->fetch_assoc()) {
		$scores[] = $row;
		$totalScore += (float)$row['score'];
		$judgeCount++;
	}
	$stmt->close();

	// Optionally compute "placement", "scoreDifference", "publishReady", etc.
	$placement       = calculatePlacement($runId, $conn);
	$scoreDifference = calculateScoreDifference($scores);
	$publishReady    = ($judgeCount === count($scores) && $scoreDifference <= 3);

	$averageScore = $judgeCount > 0 ? ($totalScore / $judgeCount) : 0.0;

	// Optionally store judge-based placement or difference
	foreach ($scores as &$score) {
		$score['placement']             = calculateJudgePlacement($score['judge'], $conn);
		$score['differenceFromAverage'] = round($score['score'] - $averageScore, 2);
	}

	$allRun1Done = isAllRun1Done($conn, $runId); 
	$isReversed  = getHeatsystemReversed($conn, $runId);

	echo json_encode([
		"success"         => true,
		"scores"          => $scores,
		"scoreDifference" => $scoreDifference,
		"publishReady"    => $publishReady
	]);
	exit;

} elseif ($method === 'POST') {
	$data = json_decode(file_get_contents("php://input"), true);

	if (!isset($data['run_id'])) {
		echo json_encode(["success" => false, "error" => "Missing run_id."]);
		exit;
	}

	$runId       = intval($data['run_id']);
	$dataSection = isset($data['data_section']) ? intval($data['data_section']) : null;

	/**
	 * Retrieve the competition code for this run
	 */
	function getCompetitionCodeByRunId($conn, $runId) {
		$sql = "
			SELECT c.code AS competition_code
			FROM runs r
			JOIN schedule s ON r.schedule = s.id
			JOIN competitions c ON s.comp = c.id
			WHERE r.id = ?
			LIMIT 1
		";
		$stmt = $conn->prepare($sql);
		$stmt->bind_param("i", $runId);
		$stmt->execute();
		$result = $stmt->get_result();
		if ($row = $result->fetch_assoc()) {
			return $row['competition_code'];  // Found it
		}
		return null; // or handle not found
	}

	/**
	 * Retrieve run number for the given runId
	 */
	function getRunNumber($conn, $runId) {
		$sql = "SELECT `run` FROM runs WHERE id=? LIMIT 1";
		$stmt = $conn->prepare($sql);
		$stmt->bind_param("i", $runId);
		$stmt->execute();
		$res = $stmt->get_result();
		if ($r = $res->fetch_assoc()) {
			return (int)$r['run'];
		}
		return 0;
	}

	// =============== If status is provided ===============
	if (isset($data['status'])) {
		$status          = intval($data['status']);
		$competitionCode = getCompetitionCodeByRunId($conn, $runId);
		$isReversed      = getHeatsystemReversed($conn, $runId);
		$runNumber       = getRunNumber($conn, $runId);

		if ($dataSection === 0) {
			// data_section=0 => update the "runs" table
			$checkRealTimeSql = "SELECT real_time FROM runs WHERE id = ? LIMIT 1";
			$stmtCheck = $conn->prepare($checkRealTimeSql);
			$stmtCheck->bind_param("i", $runId);
			$stmtCheck->execute();
			$resCheck = $stmtCheck->get_result();
			$rowCheck = $resCheck->fetch_assoc();
			$stmtCheck->close();

			// Query for runtime from settings
			$settingsQuery = "
				SELECT runtime
				FROM settings
				WHERE competition_code = ?
				LIMIT 1
			";
			$settingsStmt = $conn->prepare($settingsQuery);
			$settingsStmt->bind_param("s", $competitionCode);
			$settingsStmt->execute();
			$settingsResult = $settingsStmt->get_result();
			$settings       = $settingsResult->fetch_assoc() ?? [];
			$runtime        = $settings['runtime'] ?? 180;

			$now = time() - $runtime;

			if ($rowCheck && (empty($rowCheck['real_time']) || $rowCheck['real_time'] == 0)) {
				// If real_time is null => set it
				$updateRunQuery = "
					UPDATE runs
					SET status = ?,
						real_time = ?
					WHERE id = ?
				";
				$stmt = $conn->prepare($updateRunQuery);
				$stmt->bind_param("iii", $status, $now, $runId);
			} else {
				// Otherwise only status
				$updateRunQuery = "UPDATE runs SET status = ? WHERE id = ?";
				$stmt = $conn->prepare($updateRunQuery);
				$stmt->bind_param("ii", $status, $runId);
			}

			if ($stmt->execute()) {
				checkIfGroupComplete($conn, $runId);

				// If run=1 and reversed => call reversedStartingOrder
				if ($runNumber === 1 && $isReversed === true) {
					reversedStartingOrder($conn, $runId,$competitionCode);
				}

				echo json_encode(["success" => true, "message" => "Run status updated successfully."]);
			} else {
				echo json_encode(["success" => false, "error" => "Failed to update run status."]);
			}
			$stmt->close();
			exit;

		} elseif ($dataSection === 1) {
			// data_section=1 => update judge's status in "scores" table
			$judge = isset($data['judge']) ? intval($data['judge']) : null;
			if (!$judge) {
				echo json_encode(["success" => false, "error" => "Missing judge parameter for data_section=1."]);
				exit;
			}
			$query = "
				INSERT INTO scores (run, judge, score, status)
				VALUES (?, ?, NULL, ?)
				ON DUPLICATE KEY UPDATE status = ?
			";
			$stmt = $conn->prepare($query);
			$stmt->bind_param("iiii", $runId, $judge, $status, $status);

			if (!$stmt->execute()) {
				echo json_encode(["success" => false, "error" => "Failed to update judge status in scores."]);
				$stmt->close();
				exit;
			}
			$stmt->close();

			// Check if all judges have same status => if so, update run
			$allSameStatus = checkIfAllJudgesHaveSameStatus($conn, $runId);
			if ($allSameStatus === $status) {
				$checkRealTimeSql = "SELECT real_time FROM runs WHERE id = ? LIMIT 1";
				$stmtCheck = $conn->prepare($checkRealTimeSql);
				$stmtCheck->bind_param("i", $runId);
				$stmtCheck->execute();
				$resCheck = $stmtCheck->get_result();
				$rowCheck = $resCheck->fetch_assoc();
				$stmtCheck->close();

				$now = time();

				if ($rowCheck && (empty($rowCheck['real_time']) || $rowCheck['real_time'] == 0)) {
					$updateRunQuery = "
						UPDATE runs
						SET status = ?,
							real_time = ?
						WHERE id = ?
					";
					$stmtRun = $conn->prepare($updateRunQuery);
					$stmtRun->bind_param("iii", $status, $now, $runId);
				} else {
					$updateRunQuery = "UPDATE runs SET status = ? WHERE id = ?";
					$stmtRun = $conn->prepare($updateRunQuery);
					$stmtRun->bind_param("ii", $status, $runId);
				}
				$stmtRun->execute();
				$stmtRun->close();

				checkIfGroupComplete($conn, $runId);

				// If run=1 and reversed => reversedStartingOrder
				if ($runNumber === 1 && $isReversed === true) {
					reversedStartingOrder($conn, $runId,$competitionCode);
				}

				echo json_encode([
					"success" => true,
					"message" => "Judge status updated successfully. All judges have same status => run updated."
				]);
			} else {
				echo json_encode([
					"success" => true,
					"message" => "Judge status updated successfully. Not all judges have the same status."
				]);
			}
			exit;

		} else {
			echo json_encode([
				"success" => false,
				"error"   => "data_section must be 0 or 1 to update status."
			]);
			exit;
		}

	} elseif (isset($data['scores']) && is_array($data['scores'])) {
		// Normal path: update multiple scores
		foreach ($data['scores'] as $score) {
			$judge       = intval($score['judge']);
			$scoreValue  = $score['score'];
			$statusField = isset($score['status']) ? intval($score['status']) : 0;

			$query = "
				INSERT INTO scores (run, judge, score, status)
				VALUES (?, ?, ?, ?)
				ON DUPLICATE KEY UPDATE score = ?, status = ?
			";
			$stmt = $conn->prepare($query);
			$stmt->bind_param("iididd",
				$runId,
				$judge,
				$scoreValue,
				$statusField,
				$scoreValue,
				$statusField
			);

			if (!$stmt->execute()) {
				echo json_encode(["success" => false, "error" => "Failed to update scores."]);
				exit;
			}
		}

		echo json_encode(["success" => true, "message" => "Scores updated successfully."]);
		exit;

	} else {
		// If neither "status" nor "scores" => error
		echo json_encode(["success" => false, "error" => "Invalid input data."]);
		exit;
	}

} else {
	echo json_encode(["success" => false, "error" => "Unsupported request method."]);
	exit;
}

// Finish
$conn->close();

/*************************************************************
 * Check if the entire group containing $runId is complete
 *************************************************************/
function checkIfGroupComplete($conn, $runId) {
	// 1) find group & schedule for this run
	$groupQuery = "SELECT r.group AS group_number, r.schedule
				   FROM runs r
				   WHERE r.id = ?
				   LIMIT 1";
	$stmt = $conn->prepare($groupQuery);
	$stmt->bind_param("i", $runId);
	$stmt->execute();
	$res = $stmt->get_result();
	$groupData = $res->fetch_assoc();
	$stmt->close();

	if (!$groupData) {
		return; // no run found => do nothing
	}

	$groupNumber = intval($groupData["group_number"]);
	$scheduleId  = intval($groupData["schedule"]);

	// 2) Check how many runs are done
	$checkQuery = "
		SELECT COUNT(*) AS total_runs,
			   SUM(CASE WHEN status != 0 THEN 1 ELSE 0 END) AS done_runs
		FROM runs
		WHERE schedule = ?
		  AND `group` = ?
	";
	$stmt2 = $conn->prepare($checkQuery);
	$stmt2->bind_param("ii", $scheduleId, $groupNumber);
	$stmt2->execute();
	$checkRes = $stmt2->get_result();
	$checkData = $checkRes->fetch_assoc();
	$stmt2->close();

	if (!$checkData) {
		return;
	}

	$totalRuns = intval($checkData["total_runs"]);
	$doneRuns  = intval($checkData["done_runs"]);

	// If all done => next_round
	if ($totalRuns > 0 && $doneRuns === $totalRuns) {
		updateNextRoundAthleteId($conn, $scheduleId, $groupNumber);
		
		// make the final placement for ranking export
		finalPlacement($conn, $scheduleId, $groupNumber);
	}
}

/*************************************************************
 * checkIfAllJudgesHaveSameStatus
 *************************************************************/
function checkIfAllJudgesHaveSameStatus($conn, $runId) {
	$sql = "SELECT status FROM scores WHERE run = ?";
	$stmt = $conn->prepare($sql);
	$stmt->bind_param("i", $runId);
	$stmt->execute();
	$res = $stmt->get_result();
	$statuses = [];
	while ($row = $res->fetch_assoc()) {
		$statuses[] = (int)$row['status'];
	}
	$stmt->close();

	if (empty($statuses)) {
		return 0;  // no scores => can't unify
	}
	$first = $statuses[0];
	foreach ($statuses as $st) {
		if ($st !== $first) {
			return 0;  
		}
	}
	return $first;
}

/*************************************************************
 * calculateScoreDifference
 *************************************************************/
function calculateScoreDifference($scores) {
	$scoresArray = array_column($scores, 'score');
	if (empty($scoresArray)) {
		return 0;
	}
	return max($scoresArray) - min($scoresArray);
}

/*************************************************************
 * calculateJudgePlacement => placeholder
 *************************************************************/
function calculateJudgePlacement($judgeId, $conn) {
	// Example placeholder
	return 1;
}

/*************************************************************
 * calculatePlacement => average-based
 *************************************************************/
function calculatePlacement($runId, $conn) {
	$groupSql = "
		SELECT r.group AS group_number, r.schedule
		FROM runs r
		WHERE r.id = ?
		LIMIT 1
	";
	$stmt = $conn->prepare($groupSql);
	$stmt->bind_param("i", $runId);
	$stmt->execute();
	$res = $stmt->get_result();
	$row = $res->fetch_assoc();
	$stmt->close();

	if (!$row) {
		return 0;
	}

	$groupNumber = (int)$row['group_number'];
	$scheduleId  = (int)$row['schedule'];

	// 2) Gather all runs in that group
	$allRunsSql = "
		SELECT r.id AS run_id
		FROM runs r
		WHERE r.schedule = ?
		  AND r.group    = ?
	";
	$stmt2 = $conn->prepare($allRunsSql);
	$stmt2->bind_param("ii", $scheduleId, $groupNumber);
	$stmt2->execute();
	$res2 = $stmt2->get_result();
	$allRunIds = [];
	while ($rRow = $res2->fetch_assoc()) {
		$allRunIds[] = (int)$rRow['run_id'];
	}
	$stmt2->close();

	if (empty($allRunIds)) {
		return 0;
	}

	// 3) For each run => average of judge scores
	$runAverages = [];
	foreach ($allRunIds as $rid) {
		$scoresSql = "SELECT score FROM scores WHERE run = ?";
		$stmtScore = $conn->prepare($scoresSql);
		$stmtScore->bind_param("i", $rid);
		$stmtScore->execute();
		$scoreRes  = $stmtScore->get_result();

		$sum   = 0.0;
		$count = 0;
		while ($sRow = $scoreRes->fetch_assoc()) {
			$sum += (float)$sRow['score'];
			$count++;
		}
		$stmtScore->close();

		$avg = ($count > 0) ? ($sum / $count) : 0.0;
		$runAverages[] = [
			'run_id'   => $rid,
			'avgScore' => $avg
		];
	}

	// 4) Sort descending
	usort($runAverages, function($a, $b) {
		return $b['avgScore'] <=> $a['avgScore'];
	});

	// 5) find index => 1-based
	$placement = 0;
	foreach ($runAverages as $idx => $info) {
		if ($info['run_id'] === $runId) {
			$placement = $idx + 1;
			break;
		}
	}
	return $placement;
}

/*************************************************************
 * isAllRun1Done
 *************************************************************/
function isAllRun1Done($conn, $runId) {
	$sql = "SELECT schedule, `group` FROM runs WHERE id = ? LIMIT 1";
	$stmt = $conn->prepare($sql);
	$stmt->bind_param("i", $runId);
	$stmt->execute();
	$infoRes = $stmt->get_result();
	$infoRow = $infoRes->fetch_assoc();
	$stmt->close();

	if (!$infoRow) {
		return false;
	}

	$scheduleId = (int)$infoRow['schedule'];
	$groupNum   = (int)$infoRow['group'];

	$q = "
		SELECT COUNT(*) AS total_run1,
			   SUM(CASE WHEN status != 0 THEN 1 ELSE 0 END) AS done_run1
		FROM runs
		WHERE schedule = ?
		  AND `group` = ?
		  AND run = 1
	";
	$stmt2 = $conn->prepare($q);
	$stmt2->bind_param("ii", $scheduleId, $groupNum);
	$stmt2->execute();
	$res2 = $stmt2->get_result();
	$row2 = $res2->fetch_assoc();
	$stmt2->close();

	$totalRun1 = (int)$row2['total_run1'];
	$doneRun1  = (int)$row2['done_run1'];

	if ($totalRun1 === 0) {
		return false;
	}
	return ($doneRun1 === $totalRun1);
}

/*************************************************************
 * getHeatsystemReversed
 *************************************************************/
function getHeatsystemReversed($conn, $runId) {
	$sql = "
		SELECT h.reversed
		FROM runs r
		JOIN schedule s ON r.schedule = s.id
		JOIN heatsystem h ON s.heatsystem = h.id
		WHERE r.id = ?
		LIMIT 1
	";
	$stmt = $conn->prepare($sql);
	$stmt->bind_param("i", $runId);
	$stmt->execute();
	$res = $stmt->get_result();
	if ($row = $res->fetch_assoc()) {
		// If 'reversed' is TINYINT(0/1), cast to bool
		return (bool)$row['reversed'];
	}
	return false;
}

?>