<?php

declare(strict_types=1);

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

use App\Framework\QrCode\ValueObjects\QrCodeMatrix;
use App\Framework\QrCode\ValueObjects\QrCodeVersion;
use App\Framework\QrCode\ValueObjects\Module;
use App\Framework\QrCode\ValueObjects\ModulePosition;
use App\Framework\QrCode\ValueObjects\EncodingMode;
use App\Framework\QrCode\ValueObjects\ErrorCorrectionLevel;
use App\Framework\QrCode\Structure\FinderPattern;
use App\Framework\QrCode\Structure\TimingPattern;
use App\Framework\QrCode\Structure\AlignmentPattern;
use App\Framework\QrCode\ErrorCorrection\ReedSolomonEncoder;

echo "=== QR Code Mask Debug - Before/After Comparison ===\n\n";

// Simple data for testing
$data = "HELLO";
$version = QrCodeVersion::fromNumber(1);

// Step 1: Create matrix with function patterns
$matrix = QrCodeMatrix::create($version);
$matrix = FinderPattern::apply($matrix);
$matrix = FinderPattern::applySeparators($matrix);
$matrix = AlignmentPattern::apply($matrix);
$matrix = TimingPattern::apply($matrix);

// Add dark module
$darkModuleRow = 4 * 1 + 9;
$matrix = $matrix->setModuleAt($darkModuleRow, 8, Module::dark());

// Step 2: Encode data
$bits = '';
$bits .= '0100'; // Mode indicator (Byte)
$bits .= str_pad(decbin(strlen($data)), 8, '0', STR_PAD_LEFT); // Character count

for ($i = 0; $i < strlen($data); $i++) {
    $bits .= str_pad(decbin(ord($data[$i])), 8, '0', STR_PAD_LEFT);
}

// Terminator
$ecInfo = ReedSolomonEncoder::getECInfo(1, 'M');
$requiredBits = $ecInfo['dataCodewords'] * 8;
$terminatorLength = min(4, max(0, $requiredBits - strlen($bits)));
$bits .= str_repeat('0', $terminatorLength);

// Pad to multiple of 8
$remainder = strlen($bits) % 8;
if ($remainder !== 0) {
    $bits .= str_repeat('0', 8 - $remainder);
}

// Pad bytes
$padBytes = ['11101100', '00010001'];
$padIndex = 0;
while (strlen($bits) < $requiredBits) {
    $bits .= $padBytes[$padIndex % 2];
    $padIndex++;
}

// Convert to codewords
$dataCodewords = [];
for ($i = 0; $i < strlen($bits); $i += 8) {
    $byte = substr($bits, $i, 8);
    $dataCodewords[] = bindec($byte);
}

// Generate EC codewords
$reedSolomon = new ReedSolomonEncoder();
$ecCodewords = $reedSolomon->encode($dataCodewords, $ecInfo['ecCodewords']);

// Merge all codewords
$allCodewords = array_merge($dataCodewords, $ecCodewords);

echo "=== Encoded Data ===\n";
echo "Mode + Count + Data: " . substr($bits, 0, min(60, strlen($bits))) . "...\n";
echo "Total data codewords: " . count($dataCodewords) . "\n";
echo "Total EC codewords: " . count($ecCodewords) . "\n";
echo "First 4 data codewords: ";
for ($i = 0; $i < min(4, count($dataCodewords)); $i++) {
    echo str_pad(decbin($dataCodewords[$i]), 8, '0', STR_PAD_LEFT) . " ";
}
echo "\n\n";

// Expected encoding
echo "=== Expected Bit Sequence ===\n";
echo "Mode (Byte):     0100\n";
echo "Count (5):       00000101\n";
echo "H (72):          01001000\n";
echo "E (69):          01000101\n";
echo "L (76):          01001100\n";
echo "L (76):          01001100\n";
echo "O (79):          01001111\n";
echo "Combined first:  " . substr($bits, 0, 64) . "\n\n";

// Step 3: Place data bits (simplified - just show first few positions)
echo "=== Data Placement Analysis ===\n";

function isOccupied(int $row, int $col, int $size, int $version): bool
{
    // Finder patterns + separators
    if (
        ($row <= 8 && $col <= 8) ||
        ($row <= 8 && $col >= $size - 8) ||
        ($row >= $size - 8 && $col <= 8)
    ) {
        return true;
    }

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

    // Dark module
    if ($row === (4 * $version + 9) && $col === 8) {
        return true;
    }

    return false;
}

$size = 21;
$placementOrder = [];
$bitIdx = 0;

// Simulate placement order
for ($col = $size - 1; $col >= 1; $col -= 2) {
    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, 1)) {
                if ($bitIdx < 64) { // Only track first 64 bits
                    $placementOrder[] = [
                        'index' => $bitIdx,
                        'row' => $row,
                        'col' => $currentCol,
                        'bit' => $bits[$bitIdx] ?? '0'
                    ];
                }
                $bitIdx++;
            }
        }
    }
}

echo "First 16 bit placements:\n";
echo "Idx  Row Col  Bit  Expected\n";
for ($i = 0; $i < min(16, count($placementOrder)); $i++) {
    $p = $placementOrder[$i];
    $expected = substr($bits, $i, 1);
    $match = $p['bit'] === $expected ? '✓' : '✗';
    printf("%2d   %2d  %2d   %s    %s %s\n",
        $p['index'], $p['row'], $p['col'], $p['bit'], $expected, $match);
}

echo "\n=== Conclusion ===\n";
echo "If all bits match '✓', data placement is correct.\n";
echo "If bits don't match, there's a placement order problem.\n";
echo "Next: Check mask pattern application.\n";
