<?php
/**
 * QR Code Library - Comprehensive Test
 */

require_once __DIR__ . '/assets/vendor/phpqrcode/qrlib.php';

echo "=== QR Code Library Comprehensive Test ===\n\n";

function matrixToText($matrix, $size) {
    $out = '';
    for ($r = 0; $r < $size; $r++) {
        for ($c = 0; $c < $size; $c++) {
            $out .= $matrix[$r][$c] ? '##' : '  ';
        }
        $out .= "\n";
    }
    return $out;
}

function testGenerate($text) {
    $ref = new ReflectionClass('QRcode');
    $method = $ref->getMethod('generate');
    $method->setAccessible(true);
    return $method->invoke(null, $text);
}

function testFormatInfo($mask) {
    $ref = new ReflectionClass('QRcode');
    $method = $ref->getMethod('getFormatInfo');
    $method->setAccessible(true);
    return $method->invoke(null, $mask);
}

$pass = 0;
$fail = 0;

function check($name, $condition, $detail = '') {
    global $pass, $fail;
    if ($condition) {
        echo "  PASS: $name\n";
        $pass++;
    } else {
        echo "  FAIL: $name $detail\n";
        $fail++;
    }
}

// ============================================
// Test 1: Version selection
// ============================================
echo "Test 1: Version Selection\n";
echo str_repeat('-', 50) . "\n";

$versions = [
    1 => 1, 14 => 1, 15 => 2, 26 => 2, 27 => 3, 42 => 3,
    43 => 4, 62 => 4, 63 => 5, 84 => 5, 85 => 6, 106 => 6,
    107 => 7, 122 => 7, 123 => 8, 152 => 8, 153 => 9, 180 => 9,
    181 => 10, 213 => 10,
];

foreach ($versions as $len => $expectedVersion) {
    $text = str_repeat('A', $len);
    $qr = testGenerate($text);
    check("$len bytes -> v$expectedVersion",
          $qr['version'] === $expectedVersion,
          "(got v{$qr['version']})");
}

// ============================================
// Test 2: HELLO (version 1)
// ============================================
echo "\nTest 2: 'HELLO' encoding (v1, 21x21)\n";
echo str_repeat('-', 50) . "\n";

$qr = testGenerate("HELLO");
check("HELLO uses version 1", $qr['version'] === 1);
check("HELLO matrix is 21x21", $qr['size'] === 21);

echo "\nHELLO QR matrix:\n";
echo matrixToText($qr['matrix'], $qr['size']);

// ============================================
// Test 3: URL (46 bytes -> version 4, 33x33)
// ============================================
echo "\nTest 3: URL encoding (46 bytes -> v4, 33x33)\n";
echo str_repeat('-', 50) . "\n";

$url = "http://localhost/tap2order/menu.php?r=big-mama";
echo "URL: $url\n";
echo "URL length: " . strlen($url) . " bytes\n";

$qr = testGenerate($url);
check("URL uses version 4 (46 bytes fits in v4 capacity 62)",
      $qr['version'] === 4, "(got v{$qr['version']})");
check("URL matrix is 33x33",
      $qr['size'] === 33, "(got {$qr['size']})");

echo "\nURL QR matrix:\n";
echo matrixToText($qr['matrix'], $qr['size']);

// ============================================
// Test 4: Finder patterns
// ============================================
echo "\nTest 4: Finder Pattern Verification\n";
echo str_repeat('-', 50) . "\n";

$qr = testGenerate("HELLO");
$m = $qr['matrix'];
$s = $qr['size'];

$finder = [
    [1,1,1,1,1,1,1],
    [1,0,0,0,0,0,1],
    [1,0,1,1,1,0,1],
    [1,0,1,1,1,0,1],
    [1,0,1,1,1,0,1],
    [1,0,0,0,0,0,1],
    [1,1,1,1,1,1,1],
];

$tl = true;
for ($r = 0; $r < 7; $r++)
    for ($c = 0; $c < 7; $c++)
        if ($m[$r][$c] !== $finder[$r][$c]) $tl = false;
check("Top-left finder", $tl);

$tr = true;
for ($r = 0; $r < 7; $r++)
    for ($c = 0; $c < 7; $c++)
        if ($m[$r][$s - 7 + $c] !== $finder[$r][$c]) $tr = false;
check("Top-right finder", $tr);

$bl = true;
for ($r = 0; $r < 7; $r++)
    for ($c = 0; $c < 7; $c++)
        if ($m[$s - 7 + $r][$c] !== $finder[$r][$c]) $bl = false;
check("Bottom-left finder", $bl);

// ============================================
// Test 5: Timing patterns
// ============================================
echo "\nTest 5: Timing Patterns\n";
echo str_repeat('-', 50) . "\n";

$timing = true;
for ($i = 8; $i < $s - 8; $i++) {
    $exp = ($i % 2 == 0) ? 1 : 0;
    if ($m[6][$i] !== $exp) { $timing = false; echo "  Row 6, col $i: expected $exp got {$m[6][$i]}\n"; }
    if ($m[$i][6] !== $exp) { $timing = false; echo "  Row $i, col 6: expected $exp got {$m[$i][6]}\n"; }
}
check("Timing patterns correct", $timing);

// ============================================
// Test 6: Dark module
// ============================================
echo "\nTest 6: Dark Module\n";
echo str_repeat('-', 50) . "\n";
check("Dark module at (13,8)", $m[13][8] === 1);

// ============================================
// Test 7: Format info encoding
// ============================================
echo "\nTest 7: Format Info BCH Encoding\n";
echo str_repeat('-', 50) . "\n";

// Known format strings for EC Level M (indicator=00)
$knownFormats = [
    0 => '101010000010010',
    1 => '101000100100101',
    2 => '101111001111100',
    3 => '101101101001011',
    4 => '100010111111001',
    5 => '100000011001110',
    6 => '100111110010111',
    7 => '100101010100000',
];

foreach ($knownFormats as $mask => $expected) {
    $format = testFormatInfo($mask);
    $bin = str_pad(decbin($format), 15, '0', STR_PAD_LEFT);
    check("Mask $mask format = $expected", $bin === $expected,
          "\n    expected: $expected\n    got:      $bin");
}

// ============================================
// Test 8: Format info positions (no reserved conflicts)
// ============================================
echo "\nTest 8: Format Info Position Reservation\n";
echo str_repeat('-', 50) . "\n";

// Check that all format info positions are properly reserved
$ref = new ReflectionClass('QRcode');
$mkr = $ref->getMethod('createMatrix');
$mkr->setAccessible(true);
$result = $mkr->invoke(null, 1);
$reserved = $result['reserved'];
$size = $result['size'];

$fmtRef = $ref->getMethod('getFormatPositions');
$fmtRef->setAccessible(true);
list($fp1, $fp2) = $fmtRef->invoke(null, $size);

$allReserved = true;
$conflicts = [];
foreach (array_merge($fp1, $fp2) as $pos) {
    if (!$reserved[$pos[0]][$pos[1]]) {
        $allReserved = false;
        $conflicts[] = "({$pos[0]},{$pos[1]})";
    }
}
check("All format info positions reserved", $allReserved,
      $allReserved ? '' : "(unreserved: " . implode(', ', $conflicts) . ")");

// ============================================
// Test 9: PNG output
// ============================================
echo "\nTest 9: PNG Output\n";
echo str_repeat('-', 50) . "\n";

$tmpPng = tempnam(sys_get_temp_dir(), 'qr_') . '.png';
QRcode::png("HELLO", $tmpPng);
check("PNG created", file_exists($tmpPng));
check("PNG size > 0", filesize($tmpPng) > 0, "(size: " . filesize($tmpPng) . ")");

$hdr = file_get_contents($tmpPng, false, null, 0, 8);
check("PNG valid header", $hdr === "\x89PNG\r\n\x1a\n");
unlink($tmpPng);

// ============================================
// Test 10: SVG output
// ============================================
echo "\nTest 10: SVG Output\n";
echo str_repeat('-', 50) . "\n";

$svg = QRcode::svg("HELLO");
check("SVG XML header", strpos($svg, '<?xml') !== false);
check("SVG element", strpos($svg, '<svg') !== false);
check("SVG has rects", substr_count($svg, '<rect') > 10);

// ============================================
// Test 11: Multi-version
// ============================================
echo "\nTest 11: Multi-version Size Check\n";
echo str_repeat('-', 50) . "\n";

$tests = [
    ['text' => 'HI', 'ver' => 1],
    ['text' => str_repeat('X', 30), 'ver' => 3],
    ['text' => str_repeat('Y', 70), 'ver' => 5],
    ['text' => str_repeat('Z', 130), 'ver' => 8],
    ['text' => str_repeat('W', 200), 'ver' => 10],
];

foreach ($tests as $td) {
    $qr = testGenerate($td['text']);
    $expSz = 4 * $td['ver'] + 17;
    check("len=" . strlen($td['text']) . " -> v{$td['ver']} ({$expSz}x{$expSz})",
          $qr['version'] === $td['ver'] && $qr['size'] === $expSz,
          "(got v{$qr['version']}, {$qr['size']}x{$qr['size']})");
}

// ============================================
// Test 12: RS encoding verification
// ============================================
echo "\nTest 12: Reed-Solomon Encoding\n";
echo str_repeat('-', 50) . "\n";

$ref = new ReflectionClass('QRcode');
$gfn = $ref->getMethod('rsEncode');
$gfn->setAccessible(true);

// Encode [0x40, 0x40] with 10 EC codewords (v1)
$ec = $gfn->invoke(null, [0x40, 0x40], 10);
check("RS encode produces 10 EC codewords", count($ec) === 10);
check("RS EC codewords are all integers", array_reduce($ec, function($carry, $v) { return $carry && is_int($v); }, true));

// ============================================
// Summary
// ============================================
echo "\n" . str_repeat('=', 50) . "\n";
echo "Results: $pass passed, $fail failed\n";
echo str_repeat('=', 50) . "\n";
