<?php

declare(strict_types=1);

$method = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');

/**
 * @param array<string, mixed> $resultPayload
 */
if (!function_exists('myronQuizPublicSubmissionResultHtml')) {
    function myronQuizPublicSubmissionResultHtml(array $resultPayload): string
    {
        ob_start();
        if (!empty($resultPayload['locked']) && ($resultPayload['mode'] ?? '') === 'hard_gate') {
            require dirname(__DIR__, 2) . '/modules/quizzes/public/templates/quiz/partials/hard-gate.php';
        } elseif (!empty($resultPayload['locked'])) {
            $teaser = is_array($resultPayload['teaser'] ?? null) ? $resultPayload['teaser'] : [];
            require dirname(__DIR__, 2) . '/modules/quizzes/public/templates/quiz/partials/result-gate.php';
        } elseif (is_array($resultPayload['result'] ?? null)) {
            $result = $resultPayload['result'];
            require dirname(__DIR__, 2) . '/modules/quizzes/public/templates/quiz/partials/result.php';
        } else {
            echo '<section class="myron-quiz__result"><h2 class="myron-quiz__result-title">Your result is ready</h2></section>';
        }

        return trim((string) ob_get_clean());
    }
}

if ($method !== 'POST') {
    http_response_code(405);
    header('Allow: POST');
    echo json_encode(['success' => false, 'error' => 'method_not_allowed']);
    return;
}

$path = parse_url((string) ($_SERVER['REQUEST_URI'] ?? ''), PHP_URL_PATH) ?: '';
if (preg_match('#/api/v1/content/quizzes/([^/]+)/attempts$#', $path, $matches) !== 1) {
    http_response_code(404);
    echo json_encode(['success' => false, 'error' => 'not_found']);
    return;
}

$quizSlug = rawurldecode((string) $matches[1]);
$quiz = myronQuizDefinitionRepository()->findBySlug($quizSlug);
if (!is_array($quiz) || (string) ($quiz['status'] ?? '') !== 'published') {
    http_response_code(404);
    echo json_encode(['success' => false, 'error' => 'quiz_not_found']);
    return;
}

$raw = (string) file_get_contents('php://input');
$contentType = strtolower(trim(explode(';', (string) ($_SERVER['CONTENT_TYPE'] ?? ''), 2)[0]));
$payload = $contentType === 'application/json'
    ? (json_decode($raw, true) ?: [])
    : $_POST;
if (!is_array($payload)) {
    $payload = [];
}

$ipHash = myronFormIpHash((string) ($_SERVER['REMOTE_ADDR'] ?? ''));
myronEnsureSession();
$minuteKey = 'quiz_submit_minute_' . $ipHash . '_' . gmdate('YmdHi');
$hourKey = 'quiz_submit_hour_' . $ipHash . '_' . gmdate('YmdH');
$_SESSION[$minuteKey] = (int) ($_SESSION[$minuteKey] ?? 0) + 1;
$_SESSION[$hourKey] = (int) ($_SESSION[$hourKey] ?? 0) + 1;
if ($_SESSION[$minuteKey] > 5 || $_SESSION[$hourKey] > 30) {
    http_response_code(429);
    header('Retry-After: 60');
    echo json_encode(['success' => false, 'error' => 'rate_limited']);
    return;
}

try {
    myronPublicInteractionTokenService()->requireValidQuizTokenWithLegacySessionFallback(
        isset($payload['csrf_token']) ? (string) $payload['csrf_token'] : null,
        (string) ($quiz['slug'] ?? $quizSlug)
    );

    $version = myronQuizDefinitionRepository()->currentPublishedVersion((string) $quiz['id']);
    if (!is_array($version)) {
        http_response_code(404);
        echo json_encode(['success' => false, 'error' => 'quiz_version_not_found']);
        return;
    }

    $quizData = is_array($version['snapshot'] ?? null) ? $version['snapshot'] : [];
    $postedItems = is_array($payload['item'] ?? null) ? $payload['item'] : [];
    $attemptService = new MyronQuizAttemptService(
        myronQuizDefinitionRepository(),
        myronQuizAttemptRepository(),
        myronQuizAnalyticsEventService(),
        function_exists('myronWebhookDeliveryService') ? myronQuizAutomationService() : null
    );
    $attempt = $attemptService->startAttempt((string) $quiz['id']);

    foreach (is_array($quizData['items'] ?? null) ? $quizData['items'] : [] as $item) {
        if (!is_array($item)) {
            continue;
        }
        $itemId = (string) ($item['id'] ?? '');
        if ($itemId === '' || !array_key_exists($itemId, $postedItems)) {
            continue;
        }
        $rawValue = $postedItems[$itemId];
        $values = is_array($rawValue) ? array_values($rawValue) : [$rawValue];
        $firstValue = trim((string) ($values[0] ?? ''));
        if ($firstValue === '') {
            continue;
        }
        $optionIds = [];
        foreach (is_array($item['options'] ?? null) ? $item['options'] : [] as $option) {
            if (is_array($option) && (string) ($option['id'] ?? '') !== '') {
                $optionIds[(string) $option['id']] = true;
            }
        }
        if (isset($optionIds[$firstValue])) {
            $attemptService->saveResponse((string) $attempt['id'], $itemId, ['option_id' => $firstValue]);
            continue;
        }
        if (is_numeric($firstValue)) {
            $attemptService->saveResponse((string) $attempt['id'], $itemId, ['numeric_value' => (float) $firstValue]);
            continue;
        }
        $attemptService->saveResponse((string) $attempt['id'], $itemId, ['text_value' => $firstValue]);
    }

    $submission = $attemptService->submitAttempt((string) $attempt['id']);
    $resultPayload = is_array($submission['result'] ?? null) ? $submission['result'] : $attemptService->resultPayloadForAttempt((string) $attempt['id']);

    echo json_encode([
        'success' => true,
        'attemptId' => (string) $attempt['id'],
        'locked' => !empty($resultPayload['locked']),
        'mode' => (string) ($resultPayload['mode'] ?? 'open'),
        'resultHtml' => myronQuizPublicSubmissionResultHtml($resultPayload),
    ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
} catch (MyronCsrfFailureException $exception) {
    http_response_code(403);
    echo json_encode(['success' => false, 'error' => 'csrf_failed', 'message' => $exception->getMessage()], JSON_UNESCAPED_SLASHES);
} catch (MyronActionPreconditionError $exception) {
    http_response_code(422);
    echo json_encode(['success' => false, 'error' => 'precondition_failed', 'message' => $exception->getMessage()], JSON_UNESCAPED_SLASHES);
} catch (Throwable $exception) {
    http_response_code(500);
    $message = (string) getenv('MYRON_APP_ENV') === 'test'
        ? $exception->getMessage()
        : 'Unable to submit this quiz. Please review your answers and try again.';
    echo json_encode(['success' => false, 'error' => 'submission_failed', 'message' => $message], JSON_UNESCAPED_SLASHES);
}
