<?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 "=== QR Code Data Extraction Test ===\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 "Expected Data: '{$data}'\n";
echo "Matrix Size: {$size}x{$size}\n\n";

// Get mask pattern
$formatBits = '';
$cols = [0, 1, 2, 3, 4, 5, 7, 8, 20, 19, 18, 17, 16, 15, 14];
foreach ($cols as $col) {
    $formatBits .= $matrix->getModuleAt(8, $col)->isDark() ? '1' : '0';
}

$formatTable = [
    0 => '101010000010010',
    1 => '101000100100101',
    2 => '101111001111100',
    3 => '101101101001011',
    4 => '100010111111001',
    5 => '100000011001110',
    6 => '100111110010111',
    7 => '100101010100000',
];

$maskPattern = null;
foreach ($formatTable as $mask => $bits) {
    if ($formatBits === $bits) {
        $maskPattern = $mask;
        break;
    }
}

echo "Detected Mask Pattern: {$maskPattern}\n\n";

// Function to check if position is occupied by function pattern
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;
    }

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

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

    return false;
}

// Apply mask to get original data
function applyMask(int $row, int $col, int $maskPattern): bool
{
    return match ($maskPattern) {
        0 => ($row + $col) % 2 === 0,
        1 => $row % 2 === 0,
        2 => $col % 3 === 0,
        3 => ($row + $col) % 3 === 0,
        4 => ((int)($row / 2) + (int)($col / 3)) % 2 === 0,
        5 => (($row * $col) % 2) + (($row * $col) % 3) === 0,
        6 => ((($row * $col) % 2) + (($row * $col) % 3)) % 2 === 0,
        7 => ((($row + $col) % 2) + (($row * $col) % 3)) % 2 === 0,
        default => false
    };
}

// Extract data bits in zig-zag pattern
echo "=== Extracting Data Bits ===\n";
$dataBits = '';
$bitCount = 0;

for ($col = $size - 1; $col >= 1; $col -= 2) {
    // Skip timing column
    if ($col === 6) {
        $col--;
    }

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

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

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

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

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

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

            $dataBits .= $bit;
            $bitCount++;

            if ($bitCount <= 32) {
                echo sprintf("Bit %2d at (%2d,%2d): %d\n", $bitCount, $row, $currentCol, $bit);
            }
        }
    }
}

echo "\nTotal data bits extracted: " . strlen($dataBits) . "\n\n";

// Parse data
echo "=== Parsing Data ===\n";

// Mode indicator (4 bits)
$modeIndicator = substr($dataBits, 0, 4);
echo "Mode Indicator: {$modeIndicator} (" . bindec($modeIndicator) . ")\n";

$modeNames = [
    1 => 'Numeric',
    2 => 'Alphanumeric',
    4 => 'Byte',
    8 => 'Kanji'
];
$mode = bindec($modeIndicator);
echo "Mode: " . ($modeNames[$mode] ?? 'Unknown') . "\n\n";

// Character count (8 bits for byte mode, version 1)
$charCountBits = substr($dataBits, 4, 8);
$charCount = bindec($charCountBits);
echo "Character Count Indicator: {$charCountBits}\n";
echo "Character Count: {$charCount}\n\n";

// Data bytes
echo "Data Bytes:\n";
$offset = 12;
$decodedData = '';
for ($i = 0; $i < $charCount; $i++) {
    $byteBits = substr($dataBits, $offset + ($i * 8), 8);
    $byte = bindec($byteBits);
    $char = chr($byte);
    $decodedData .= $char;
    echo sprintf("Byte %2d: %s = %3d = '%s'\n", $i + 1, $byteBits, $byte, $char);
}

echo "\n=== Result ===\n";
echo "Expected: '{$data}'\n";
echo "Decoded:  '{$decodedData}'\n";
echo ($decodedData === $data ? "✅ MATCH!" : "❌ MISMATCH!") . "\n";
