<?php

declare(strict_types=1);

require_once __DIR__ . '/../../vendor/autoload.php';

use App\Framework\QrCode\QrCodeGenerator;
use App\Framework\QrCode\ValueObjects\ErrorCorrectionLevel;
use App\Framework\QrCode\ValueObjects\QrCodeConfig;
use App\Framework\QrCode\ValueObjects\QrCodeVersion;
use App\Framework\QrCode\ValueObjects\EncodingMode;

echo "=== Data Placement Order Verification ===\n\n";

$data = "HELLO WORLD";
$config = new QrCodeConfig(
    version: QrCodeVersion::fromNumber(1),
    errorCorrectionLevel: ErrorCorrectionLevel::M,
    encodingMode: EncodingMode::BYTE
);

$matrix = QrCodeGenerator::generate($data, $config);
$size = $matrix->getSize();

echo "Testing Data Placement for Version 1 (21x21)\n\n";

// Laut ISO/IEC 18004: Data placement beginnt bottom-right, geht nach oben
// Dann zwei Spalten nach links, geht nach unten, usw.

// Simulate data placement to verify order
function isOccupied(int $row, int $col, int $size): bool
{
    // Finder patterns + separators
    if (
        ($row <= 8 && $col <= 8) ||
        ($row <= 7 && $col >= $size - 8) ||
        ($row >= $size - 8 && $col <= 7)
    ) {
        return true;
    }

    // Timing patterns
    if ($row === 6 || $col === 6) return true;

    // Format information
    if ($row === 8 || $col === 8) return true;

    // Dark module
    if ($row === 13 && $col === 8) return true;

    return false;
}

echo "First 20 data positions (should be in zigzag pattern):\n";
$positions = [];
$count = 0;

for ($col = $size - 1; $col >= 1 && $count < 20; $col -= 2) {
    if ($col === 6) $col--;

    $upward = ((int)(($size - 1 - $col) / 2) % 2) === 0;

    for ($i = 0; $i < $size && $count < 20; $i++) {
        $row = $upward ? ($size - 1 - $i) : $i;

        for ($c = 0; $c < 2 && $count < 20; $c++) {
            $currentCol = $col - $c;

            if (isOccupied($row, $currentCol, $size)) continue;

            $count++;
            $positions[] = "({$row},{$currentCol})";

            if ($count <= 20) {
                echo sprintf("Position %2d: (%2d,%2d)\n", $count, $row, $currentCol);
            }
        }
    }
}

echo "\n=== Expected vs Actual First Bits ===\n";

// Expected data (from encoding):
// Mode: 0100 (Byte)
// Count: 00001011 (11 characters)
// First char 'H': 01001000

$expectedBits = "0100" . "00001011" . "01001000";
echo "Expected first 20 bits: {$expectedBits}\n";

// Get actual bits from matrix
function applyMask(int $row, int $col, int $mask): bool
{
    return match ($mask) {
        2 => $col % 3 === 0,  // Current mask
        default => false
    };
}

$actualBits = '';
$count = 0;

for ($col = $size - 1; $col >= 1 && $count < 20; $col -= 2) {
    if ($col === 6) $col--;

    $upward = ((int)(($size - 1 - $col) / 2) % 2) === 0;

    for ($i = 0; $i < $size && $count < 20; $i++) {
        $row = $upward ? ($size - 1 - $i) : $i;

        for ($c = 0; $c < 2 && $count < 20; $c++) {
            $currentCol = $col - $c;

            if (isOccupied($row, $currentCol, $size)) continue;

            $module = $matrix->getModuleAt($row, $currentCol);
            $bit = $module->isDark() ? 1 : 0;

            // Unmask
            if (applyMask($row, $currentCol, 2)) {
                $bit = $bit === 1 ? 0 : 1;
            }

            $actualBits .= $bit;
            $count++;
        }
    }
}

echo "Actual first 20 bits:   {$actualBits}\n\n";

// Compare
$matches = 0;
for ($i = 0; $i < 20; $i++) {
    if ($expectedBits[$i] === $actualBits[$i]) {
        $matches++;
    } else {
        echo "❌ Bit {$i}: expected {$expectedBits[$i]}, got {$actualBits[$i]}\n";
    }
}

echo "\nMatch: {$matches}/20 bits\n";

if ($matches === 20) {
    echo "✅ Data placement order is CORRECT!\n";
} else {
    echo "❌ Data placement order is WRONG!\n";
}

// Visualisiere die ersten Data-Positionen
echo "\n=== Visual Data Placement Map ===\n";
echo "Legend: # = Function Pattern, D = Data (numbered)\n\n";

$dataMap = [];
for ($r = 0; $r < $size; $r++) {
    $dataMap[$r] = [];
    for ($c = 0; $c < $size; $c++) {
        $dataMap[$r][$c] = isOccupied($r, $c, $size) ? '#' : ' ';
    }
}

// Mark first 20 data positions
$count = 0;
for ($col = $size - 1; $col >= 1 && $count < 20; $col -= 2) {
    if ($col === 6) $col--;

    $upward = ((int)(($size - 1 - $col) / 2) % 2) === 0;

    for ($i = 0; $i < $size && $count < 20; $i++) {
        $row = $upward ? ($size - 1 - $i) : $i;

        for ($c = 0; $c < 2 && $count < 20; $c++) {
            $currentCol = $col - $c;

            if (isOccupied($row, $currentCol, $size)) continue;

            $count++;
            $dataMap[$row][$currentCol] = (string)($count % 10);
        }
    }
}

// Print map
echo "   ";
for ($c = 0; $c < $size; $c++) {
    echo str_pad((string)$c, 2, ' ', STR_PAD_LEFT);
}
echo "\n";

for ($r = 0; $r < $size; $r++) {
    echo str_pad((string)$r, 2, ' ', STR_PAD_LEFT) . ' ';
    for ($c = 0; $c < $size; $c++) {
        echo $dataMap[$r][$c] . ' ';
    }
    echo "\n";
}
