<?php
require_once '../db.php';

const MAX_OTP_ATTEMPTS = 3;

function ensureOtpAttemptsColumn(mysqli $conn): void
{
    $columnCheck = $conn->query("SHOW COLUMNS FROM reservation_email_verifications LIKE 'failed_attempts'");
    if ($columnCheck && $columnCheck->num_rows > 0) {
        $columnCheck->close();
        return;
    }

    if ($columnCheck) {
        $columnCheck->close();
    }

    $conn->query(
        "ALTER TABLE reservation_email_verifications
         ADD COLUMN failed_attempts TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER otp_hash"
    );
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(["success" => false, "message" => "Method not allowed"]);
    exit;
}

$data = json_decode(file_get_contents("php://input"), true);
if (!is_array($data)) {
    $data = [];
}

$email = trim((string) ($data["email"] ?? ""));
$otpCode = trim((string) ($data["otpCode"] ?? ""));
$otpToken = trim((string) ($data["otpToken"] ?? ""));

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    http_response_code(422);
    echo json_encode(["success" => false, "message" => "Please enter a valid email address."]);
    exit;
}

if (!preg_match('/^\d{6}$/', $otpCode)) {
    http_response_code(422);
    echo json_encode(["success" => false, "message" => "Verification code must be 6 digits."]);
    exit;
}

if ($otpToken === "") {
    http_response_code(422);
    echo json_encode(["success" => false, "message" => "Verification session token is missing."]);
    exit;
}

ensureOtpAttemptsColumn($conn);

$stmt = $conn->prepare(
    "SELECT id, otp_hash, expires_at, verified_at, used_at, failed_attempts
     FROM reservation_email_verifications
     WHERE email = ? AND otp_token = ?
     ORDER BY id DESC
     LIMIT 1"
);

if (!$stmt) {
    http_response_code(500);
    echo json_encode(["success" => false, "message" => "Unable to prepare verification lookup."]);
    exit;
}

$stmt->bind_param("ss", $email, $otpToken);
$stmt->execute();
$result = $stmt->get_result();
$row = $result ? $result->fetch_assoc() : null;
$stmt->close();

if (!$row) {
    http_response_code(404);
    echo json_encode(["success" => false, "message" => "Verification session not found. Please request a new code."]);
    exit;
}

if (!empty($row["used_at"])) {
    http_response_code(409);
    echo json_encode(["success" => false, "message" => "This verification session is no longer active. Please request a new code."]);
    exit;
}

if (!empty($row["verified_at"])) {
    http_response_code(409);
    echo json_encode(["success" => false, "message" => "This email is already verified for this session."]);
    exit;
}

$failedAttempts = (int) ($row["failed_attempts"] ?? 0);
if ($failedAttempts >= MAX_OTP_ATTEMPTS) {
    $lockStmt = $conn->prepare("UPDATE reservation_email_verifications SET used_at = NOW() WHERE id = ?");
    if ($lockStmt) {
        $verificationId = (int) $row["id"];
        $lockStmt->bind_param("i", $verificationId);
        $lockStmt->execute();
        $lockStmt->close();
    }

    http_response_code(409);
    echo json_encode([
        "success" => false,
        "message" => "Maximum verification attempts reached. Please request a new code."
    ]);
    exit;
}

$expiresAtTimestamp = strtotime((string) $row["expires_at"]);
if ($expiresAtTimestamp === false || $expiresAtTimestamp < time()) {
    $expireStmt = $conn->prepare("UPDATE reservation_email_verifications SET used_at = NOW() WHERE id = ?");
    if ($expireStmt) {
        $verificationId = (int) $row["id"];
        $expireStmt->bind_param("i", $verificationId);
        $expireStmt->execute();
        $expireStmt->close();
    }

    http_response_code(410);
    echo json_encode(["success" => false, "message" => "Verification code expired. Please request a new code."]);
    exit;
}

$expectedHash = (string) $row["otp_hash"];
$receivedHash = hash("sha256", $otpCode);

if (!hash_equals($expectedHash, $receivedHash)) {
    $verificationId = (int) $row["id"];
    $nextAttempt = $failedAttempts + 1;
    $remainingAttempts = MAX_OTP_ATTEMPTS - $nextAttempt;

    if ($nextAttempt >= MAX_OTP_ATTEMPTS) {
        $failStmt = $conn->prepare(
            "UPDATE reservation_email_verifications
             SET failed_attempts = ?, used_at = NOW()
             WHERE id = ?"
        );
        if ($failStmt) {
            $failStmt->bind_param("ii", $nextAttempt, $verificationId);
            $failStmt->execute();
            $failStmt->close();
        }

        http_response_code(401);
        echo json_encode([
            "success" => false,
            "message" => "Invalid verification code. Maximum attempts reached. Please request a new code."
        ]);
        exit;
    }

    $attemptStmt = $conn->prepare(
        "UPDATE reservation_email_verifications SET failed_attempts = ? WHERE id = ?"
    );
    if ($attemptStmt) {
        $attemptStmt->bind_param("ii", $nextAttempt, $verificationId);
        $attemptStmt->execute();
        $attemptStmt->close();
    }

    http_response_code(401);
    echo json_encode([
        "success" => false,
        "message" => "Invalid verification code. {$remainingAttempts} attempt(s) remaining."
    ]);
    exit;
}

$verifiedToken = bin2hex(random_bytes(32));
$verificationExpiry = date("Y-m-d H:i:s", time() + (30 * 60));
$verificationId = (int) $row["id"];

$updateStmt = $conn->prepare(
    "UPDATE reservation_email_verifications
     SET verified_at = NOW(),
         verified_token = ?,
         verification_expires_at = ?,
         otp_hash = '',
         failed_attempts = 0
     WHERE id = ?"
);

if (!$updateStmt) {
    http_response_code(500);
    echo json_encode(["success" => false, "message" => "Unable to prepare verification update."]);
    exit;
}

$updateStmt->bind_param("ssi", $verifiedToken, $verificationExpiry, $verificationId);
if (!$updateStmt->execute()) {
    http_response_code(500);
    echo json_encode(["success" => false, "message" => "Unable to verify email. Please try again."]);
    $updateStmt->close();
    exit;
}

$updateStmt->close();

echo json_encode([
    "success" => true,
    "message" => "Email verified successfully.",
    "verificationToken" => $verifiedToken,
    "expiresInSeconds" => 1800
]);

$conn->close();
