<?php

ini_set('display_errors', '0');
error_reporting(E_ALL);
ob_start();

header('Content-Type: application/json');

set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
    error_log('[ai_repair_question] PHP warning: ' . $message . ' in ' . $file . ':' . $line);

    return true;
});

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../ai/form_generator_retry.php';
require_once __DIR__ . '/../ai/form_generator_question_validation.php';
require_once __DIR__ . '/../../prompts/sba_ai_repair_prompt.php';

/**
 * @param array<string, mixed> $payload
 */
function aiRepairJsonResponse(array $payload): void
{
    while (ob_get_level() > 0) {
        ob_end_clean();
    }
    echo json_encode($payload, JSON_UNESCAPED_UNICODE);
    exit;
}

/**
 * @param array<string, mixed> $entry
 */
function aiRepairTraceLog(array $entry): void
{
    $logDir = dirname(__DIR__, 2) . '/logs';
    if (!is_dir($logDir)) {
        @mkdir($logDir, 0755, true);
    }
    @file_put_contents(
        $logDir . '/sba_ai_repair_trace.log',
        json_encode($entry, JSON_UNESCAPED_UNICODE) . "\n",
        FILE_APPEND | LOCK_EX
    );
}

function aiRepairTimedOutOrNoBytes(array $fetch): bool
{
    $timedOut = !empty($fetch['timed_out']);
    $responseLen = (int) ($fetch['response_len'] ?? 0);
    $httpStatus = (int) ($fetch['http_status'] ?? 0);
    if ($timedOut) {
        return true;
    }
    if ($responseLen === 0 && $httpStatus === 0) {
        return true;
    }
    $err = mb_strtolower((string) ($fetch['error'] ?? ''));

    return str_contains($err, 'timed out');
}

function aiRepairSafeFailMessage(string $detail): array
{
    return [
        'ok' => false,
        'status' => 'error',
        'message' => 'AI repair timed out. Original draft unchanged. You can try again or continue with manual review.',
        'error' => 'AI repair failed',
        'detail' => $detail,
    ];
}

try {
    $question_id = trim((string) ($_POST['question_id'] ?? ''));

    if ($question_id === '') {
        aiRepairJsonResponse(aiRepairSafeFailMessage('Missing question ID.'));
    }

    $sql = 'SELECT * FROM questions WHERE id = :question_id LIMIT 1';
    $stmt = $pdo->prepare($sql);
    $stmt->execute(['question_id' => $question_id]);
    $question = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$question) {
        aiRepairJsonResponse(aiRepairSafeFailMessage('Question not found.'));
    }

    if (($question['source_type'] ?? '') !== 'generated') {
        aiRepairJsonResponse(aiRepairSafeFailMessage('AI repair is only available for generated SBA questions.'));
    }

    $question = formGeneratorApplyStyleRepairToQuestionRow($question);

    $aiReviewRaw = $_POST['ai_review'] ?? '';
    if (!is_string($aiReviewRaw) || trim($aiReviewRaw) === '') {
        aiRepairJsonResponse(aiRepairSafeFailMessage('AI repair requires Reviewer 1 output (ai_review). Run Review with AI first.'));
    }

    $aiReview = json_decode($aiReviewRaw, true);
    if (!is_array($aiReview)) {
        aiRepairJsonResponse(aiRepairSafeFailMessage('Invalid ai_review JSON.'));
    }

    $styleWarnings = [];
    $warningsRaw = $_POST['style_warnings'] ?? '';
    if (is_string($warningsRaw) && $warningsRaw !== '') {
        $decoded = json_decode($warningsRaw, true);
        if (is_array($decoded)) {
            $styleWarnings = $decoded;
        }
    }

    if ($styleWarnings === []) {
        $styleWarnings = formGeneratorStyleWarningsForQuestionRow($question, $pdo);
    }

    $preBlock = sbaAiRepairShouldBlockAutomaticRepair($question, $aiReview);
    if ($preBlock['block']) {
        aiRepairJsonResponse([
            'ok' => true,
            'status' => 'success',
            'message' => 'Automatic repair blocked: clinical safety concern. Original draft unchanged. Run Reviewer 2 clinical safety check on the original draft.',
            'ai_repair' => sbaAiRepairBuildBlockedRepairData($question, $preBlock['reasons']),
            'validator_after_repair' => [],
            'repaired_at' => gmdate('c'),
        ]);
    }

    $lockedContext = formGeneratorLockedQuestionContext($question);
    $prompt = buildSbaAiRepairPrompt($question, $aiReview, $styleWarnings, $lockedContext);
    $model = formGeneratorOpenAiSbaRepairModel();
    $promptChars = strlen($prompt);
    $attempts = 2;
    $lastFetch = null;
    $fetch = null;

    for ($attempt = 1; $attempt <= $attempts; ++$attempt) {
        $started = microtime(true);
        aiRepairTraceLog([
            'event' => 'repair_attempt_started',
            'time' => gmdate('c'),
            'attempt' => $attempt,
            'question_id' => (string) $question_id,
            'skill' => (string) ($question['skill'] ?? ''),
            'model' => $model,
            'prompt_char_count' => $promptChars,
            'curl_timeout_seconds' => 110,
            'openai_call_started' => true,
        ]);

        $fetch = formGeneratorOpenAiChatJsonQuestion($prompt, '', 0, 0.25, $model);
        $lastFetch = $fetch;
        $elapsed = (int) round((microtime(true) - $started) * 1000);

        aiRepairTraceLog([
            'event' => 'repair_attempt_finished',
            'time' => gmdate('c'),
            'attempt' => $attempt,
            'question_id' => (string) $question_id,
            'skill' => (string) ($question['skill'] ?? ''),
            'model' => $model,
            'elapsed_ms' => $elapsed,
            'openai_call_returned' => true,
            'http_status' => (int) ($fetch['http_status'] ?? 0),
            'response_len' => (int) ($fetch['response_len'] ?? 0),
            'timed_out' => !empty($fetch['timed_out']),
            'json_parse_attempted' => true,
            'json_parse_succeeded' => (bool) ($fetch['ok'] ?? false),
            'retry_attempted' => $attempt > 1,
        ]);

        if (!($fetch['ok'] ?? false) && aiRepairTimedOutOrNoBytes($fetch) && $attempt < $attempts) {
            continue;
        }
        break;
    }

    if (!$fetch || !$fetch['ok'] || !is_array($fetch['data'])) {
        aiRepairJsonResponse(aiRepairSafeFailMessage(
            ($lastFetch && aiRepairTimedOutOrNoBytes($lastFetch))
                ? 'OpenAI request timed out.'
                : (($lastFetch['error'] ?? '') !== '' ? (string) $lastFetch['error'] : 'AI repair failed.')
        ));
    }

    $normalized = normalizeSbaAiRepairResponse($fetch['data'], $question);
    if (!$normalized['ok'] || !is_array($normalized['data'])) {
        aiRepairJsonResponse(aiRepairSafeFailMessage(
            $normalized['error'] !== '' ? $normalized['error'] : 'AI repair returned JSON that could not be validated.'
        ));
    }

    $aiRepairPayload = $normalized['data'];
    $validatorAfterRepair = [];
    if (!empty($aiRepairPayload['repair_blocked'])) {
        aiRepairJsonResponse([
            'ok' => true,
            'status' => 'success',
            'message' => 'Automatic repair blocked: clinical safety concern. Original draft unchanged. Run Reviewer 2 clinical safety check on the original draft.',
            'ai_repair' => $aiRepairPayload,
            'validator_after_repair' => [],
            'repaired_at' => gmdate('c'),
        ]);
    }

    if (is_array($aiRepairPayload['repaired_question'] ?? null)) {
        $repairedRow = formGeneratorMergeQuestionRowWithContentOverride(
            $question,
            $aiRepairPayload['repaired_question']
        );
        $validatorAfterRepair = formGeneratorStyleWarningsForQuestionRow($repairedRow, $pdo);
    }

    aiRepairJsonResponse([
        'ok' => true,
        'status' => 'success',
        'message' => 'AI repair preview complete.',
        'ai_repair' => $aiRepairPayload,
        'validator_after_repair' => $validatorAfterRepair,
        'repaired_at' => gmdate('c'),
    ]);
} catch (Throwable $e) {
    error_log('[ai_repair_question] Exception: ' . $e->getMessage());
    aiRepairJsonResponse(aiRepairSafeFailMessage('Unexpected server error during AI repair.'));
} finally {
    restore_error_handler();
}
