<?php
declare(strict_types=1);

require_once dirname(__DIR__) . '/db_bootstrap.php';
require_once dirname(__DIR__) . '/messages_lib.php';
require_once dirname(__DIR__) . '/settings_store.php';

$conn = ensure_db(true);
ensure_message_queue_tables($conn);
settings_ensure_table($conn);

/*
 * Shadow the production tables for this connection. This exercises the real
 * queue implementation without assigning or sending any existing messages.
 */
foreach (['message_queue_runs', 'message_outbox', 'message_logs', 'message_campaigns', 'app_settings'] as $table) {
    $schemaResult = $conn->query("SHOW CREATE TABLE `{$table}`");
    $schemaRow = $schemaResult ? $schemaResult->fetch_assoc() : [];
    $createSql = (string)($schemaRow['Create Table'] ?? '');
    $createSql = preg_replace('/^CREATE TABLE /i', 'CREATE TEMPORARY TABLE ', $createSql, 1);
    $createSql = preg_replace('/,\R\s*CONSTRAINT\s+`[^`]+`\s+FOREIGN KEY[^\r\n]*/i', '', $createSql);
    if ($createSql === '' || !$conn->query($createSql)) {
        throw new RuntimeException("Unable to isolate {$table}: " . $conn->error);
    }
}

$assert = static function (bool $condition, string $message): void {
    if (!$condition) {
        throw new RuntimeException($message);
    }
};

$config = [
    'enabled' => '1',
    'mode' => 'local',
    'test_phone' => '0990000000',
    'queue_confirmation_required' => '1',
];
setting_set($conn, 'sms_provider', $config);

$conn->query("INSERT INTO message_outbox
  (template_key,to_phone,channel,body,status)
  VALUES
  ('__TEST_FIRST_APPROVAL__','0990000001','sms','first campaign body','QUEUED'),
  ('__TEST_FIRST_APPROVAL__','0990000002','sms','second campaign body','QUEUED')");

$testCalls = [];
$testSender = static function (mysqli $db, string $phone, string $body) use (&$testCalls): array {
    $testCalls[] = ['phone' => $phone, 'body' => $body];
    return ['ok' => true, 'message_id' => 'isolated-test-message'];
};

$created = messages_queue_create_run($conn, 77, $testSender);
$run = $created['run'] ?? [];
$assert(!empty($created['ok']), 'The confirmation-required run was not created.');
$assert(count($testCalls) === 1, 'The test message was not sent exactly once.');
$assert(($testCalls[0]['phone'] ?? '') === '0990000000', 'The configured test number was not used first.');
$assert(($testCalls[0]['body'] ?? '') === 'first campaign body', 'The first queued campaign body was not used for the test.');
$assert(($run['status'] ?? '') === 'WAITING_CONFIRMATION', 'The run did not stop for approval after the test message.');
$assert(!empty($run['test_sent']), 'The run did not record the successful test message.');

$subscriberSendCalls = 0;
$subscriberSender = static function (mysqli $db, array $row) use (&$subscriberSendCalls): array {
    $subscriberSendCalls++;
    return ['ok' => true, 'message_id' => 'isolated-subscriber-message'];
};

$blockedStep = messages_queue_process_step($conn, (int)$run['id'], 10, $subscriberSender);
$assert(!empty($blockedStep['ok']), 'The waiting run could not be inspected.');
$assert($subscriberSendCalls === 0, 'A subscriber message was sent before approval.');
$assert((($blockedStep['run'] ?? [])['status'] ?? '') === 'WAITING_CONFIRMATION', 'The run left the approval gate unexpectedly.');

$approved = messages_queue_control_run($conn, (int)$run['id'], 'approve');
$assert(!empty($approved['ok']), 'The run approval failed.');
$assert((($approved['run'] ?? [])['status'] ?? '') === 'RUNNING', 'Approval did not release the queue.');

$completed = messages_queue_process_step($conn, (int)$run['id'], 10, $subscriberSender);
$assert(!empty($completed['ok']), 'The approved run did not process.');
$assert($subscriberSendCalls === 2, 'The approved run did not send all subscriber messages.');
$assert((($completed['run'] ?? [])['status'] ?? '') === 'COMPLETED', 'The approved run did not complete.');

$config['queue_confirmation_required'] = '0';
setting_set($conn, 'sms_provider', $config);
$conn->query("INSERT INTO message_outbox
  (template_key,to_phone,channel,body,status)
  VALUES ('__TEST_FIRST_AUTO__','0990000003','sms','automatic campaign body','QUEUED')");

$autoTestCalls = [];
$autoCreated = messages_queue_create_run(
    $conn,
    77,
    static function (mysqli $db, string $phone, string $body) use (&$autoTestCalls): array {
        $autoTestCalls[] = ['phone' => $phone, 'body' => $body];
        return ['ok' => true, 'message_id' => 'isolated-auto-test'];
    }
);
$autoRun = $autoCreated['run'] ?? [];
$assert(!empty($autoCreated['ok']), 'The automatic run was not created.');
$assert(count($autoTestCalls) === 1, 'The automatic run skipped or duplicated its test message.');
$assert(($autoTestCalls[0]['phone'] ?? '') === '0990000000', 'The automatic run did not send to the test number first.');
$assert(($autoTestCalls[0]['body'] ?? '') === 'automatic campaign body', 'The automatic run used the wrong test body.');
$assert(($autoRun['status'] ?? '') === 'RUNNING', 'The automatic run did not start after its successful test.');
$assert(empty($autoRun['confirmation_required']), 'The automatic run incorrectly required approval.');

$autoSubscriberCalls = 0;
$autoCompleted = messages_queue_process_step(
    $conn,
    (int)$autoRun['id'],
    10,
    static function (mysqli $db, array $row) use (&$autoSubscriberCalls): array {
        $autoSubscriberCalls++;
        return ['ok' => true, 'message_id' => 'isolated-auto-subscriber'];
    }
);
$assert($autoSubscriberCalls === 1, 'The automatic run did not continue after its test.');
$assert((($autoCompleted['run'] ?? [])['status'] ?? '') === 'COMPLETED', 'The automatic run did not complete.');

echo "PASS test message is first and approval gates subscriber delivery" . PHP_EOL;
