<?php
/*** This text should be at the top of all code files ***
 * index.php – used for QR code generation in normal and demo mode
 * Made by: Morten Pilekær
 * Rev. 0.4.0 Owner: Morten Pilekær
 * Location: /qr-app-lite/index.php
 ***/
declare(strict_types=1);

require_once __DIR__ . '/app-config.php';

$autoload = __DIR__ . '/vendor/autoload.php';
if (!file_exists($autoload)) {
    http_response_code(500);
    echo '<!doctype html><html lang="da"><head><meta charset="utf-8"><title>Fejl</title></head><body>';
    echo '<h1>Fejl</h1><p>Mangler <code>vendor/autoload.php</code>. Kør: <code>composer require endroid/qr-code:^5.0</code></p>';
    echo '</body></html>';
    exit;
}
require $autoload;

use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\RoundBlockSizeMode;
use Endroid\QrCode\Writer\Result\GdResult;
use Endroid\QrCode\Writer\PngWriter;

$errors = [];
$messages = [];
$localPath = null;
$inlineDataUri = null;
$downloadFilename = null;
$outputStats = ['count' => 0, 'size_bytes' => 0];
$isPublicDemo = isQrPublicDemo();

function mapEcLevel(string $s): ErrorCorrectionLevel
{
    return match (strtoupper($s)) {
        'L' => ErrorCorrectionLevel::Low,
        'M' => ErrorCorrectionLevel::Medium,
        'Q' => ErrorCorrectionLevel::Quartile,
        'H' => ErrorCorrectionLevel::High,
        default => ErrorCorrectionLevel::Medium,
    };
}

function selected(string $value, string $selectedValue): string
{
    return $value === $selectedValue ? ' selected' : '';
}

function normalizeOutputFormat(string $format): string
{
    return match (strtoupper($format)) {
        'JPEG' => 'jpeg',
        'TIFF' => 'tiff',
        default => 'png',
    };
}

function outputFormatLabel(string $format): string
{
    return match ($format) {
        'jpeg' => 'JPEG',
        'tiff' => 'TIFF',
        default => 'PNG',
    };
}

function outputFormatMimeType(string $format): string
{
    return match ($format) {
        'jpeg' => 'image/jpeg',
        'tiff' => 'image/tiff',
        default => 'image/png',
    };
}

function createJpegQrImage(GdResult $result, ?string $fullPath = null): string
{
    $sourceImage = $result->getImage();
    $width = imagesx($sourceImage);
    $height = imagesy($sourceImage);
    $jpegImage = imagecreatetruecolor($width, $height);

    if (!$jpegImage) {
        throw new RuntimeException('Kunne ikke oprette JPEG-billede.');
    }

    $white = imagecolorallocate($jpegImage, 255, 255, 255);
    if ($white === false) {
        imagedestroy($jpegImage);
        throw new RuntimeException('Kunne ikke oprette JPEG-baggrund.');
    }

    imagefill($jpegImage, 0, 0, $white);
    imagecopy($jpegImage, $sourceImage, 0, 0, 0, 0, $width, $height);

    ob_start();
    $encoded = imagejpeg($jpegImage, null, 95);
    $jpegString = (string)ob_get_clean();
    imagedestroy($jpegImage);

    if (!$encoded || $jpegString === '') {
        throw new RuntimeException('Kunne ikke generere JPEG-billedet.');
    }

    if ($fullPath !== null && file_put_contents($fullPath, $jpegString, LOCK_EX) === false) {
        throw new RuntimeException('Kunne ikke gemme JPEG-filen.');
    }

    return $jpegString;
}

if (!extension_loaded('gd')) {
    $errors[] = 'PHP-udvidelsen gd er ikke aktiv. Aktiver den i php.ini for billedgenerering.';
}

if (!$isPublicDemo) {
    try {
        $cleanup = cleanupQrOutputDirectory();
        if ($cleanup['deleted'] > 0) {
            $messages[] = 'Automatisk oprydning fjernede ' . (int)$cleanup['deleted'] . ' gamle QR-fil(er).';
        }
        if ($cleanup['errors']) {
            $errors[] = 'Oprydning kunne ikke slette enkelte gamle QR-filer. Kontrollér rettigheder i mappen ' . QR_OUTPUT_DIR_NAME . '.';
        }
        $outputStats = getQrOutputStats();
    } catch (Throwable $e) {
        $errors[] = 'Output-mappe fejl: ' . $e->getMessage();
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $text   = trim((string)($_POST['text'] ?? ''));
    $size   = (int)($_POST['size'] ?? 300);
    $margin = (int)($_POST['margin'] ?? 8);
    $ecRaw  = strtoupper((string)($_POST['ec'] ?? 'M'));
    $ec     = mapEcLevel($ecRaw);
    $outputFormat = normalizeOutputFormat((string)($_POST['format'] ?? 'png'));

    if ($text === '') {
        $errors[] = 'Tekst/URL må ikke være tom.';
    }
    if ((function_exists('mb_strlen') ? mb_strlen($text, 'UTF-8') : strlen($text)) > QR_INPUT_MAX_LENGTH) {
        $errors[] = 'Indholdet er for langt. Maksimum er ' . QR_INPUT_MAX_LENGTH . ' tegn.';
    }
    if ($size < 100 || $size > 2000) {
        $errors[] = 'Størrelse skal være 100–2000 px.';
    }
    if ($margin < 0 || $margin > 64) {
        $errors[] = 'Margin skal være 0–64 px.';
    }
    if (!in_array($ecRaw, ['L', 'M', 'Q', 'H'], true)) {
        $errors[] = 'Fejlkorrigering skal være L, M, Q eller H.';
    }
    if ($outputFormat === 'tiff') {
        $errors[] = 'TIFF er valgt, men TIFF-export understottes ikke endnu i den lokale generator.';
    }

    if (!$errors) {
        try {
            $outputDir = $isPublicDemo ? null : ensureQrOutputDirectory();

            $builder = Builder::create()
                ->writer(new PngWriter())
                ->data($text)
                ->encoding(new Encoding('UTF-8'))
                ->errorCorrectionLevel($ec)
                ->size($size)
                ->margin($margin)
                ->roundBlockSizeMode(RoundBlockSizeMode::Margin);

            $result = $builder->build();

            $downloadFilename = 'qr_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $outputFormat;
            $fullPath = $outputDir === null ? null : $outputDir . DIRECTORY_SEPARATOR . $downloadFilename;
            $inlineDataUri = null;

            if ($outputFormat === 'jpeg') {
                $imageString = createJpegQrImage($result, $fullPath);
                $inlineDataUri = 'data:' . outputFormatMimeType($outputFormat) . ';base64,' . base64_encode($imageString);
            } else {
                $inlineDataUri = $result->getDataUri();
                if ($fullPath !== null) {
                    $result->saveToFile($fullPath);
                }
            }

            if ($isPublicDemo) {
                $messages[] = 'QR-koden er genereret som ' . outputFormatLabel($outputFormat) . ' uden at blive gemt. Download den, før du forlader siden.';
            } else {
                $localPath = appPublicPath(QR_OUTPUT_DIR_NAME . '/' . $downloadFilename);
                $messages[] = 'QR-koden er genereret som ' . outputFormatLabel($outputFormat) . ' og gemt i mappen ' . QR_OUTPUT_DIR_NAME . '.';
                $outputStats = getQrOutputStats();
            }
        } catch (Throwable $e) {
            $errors[] = 'Fejl under generering: ' . $e->getMessage();
        }
    }
}

$selectedEc = strtoupper((string)($_POST['ec'] ?? 'M'));
$textValue = isset($_POST['text']) ? (string)$_POST['text'] : '';
$sizeValue = isset($_POST['size']) ? (int)$_POST['size'] : 300;
$marginValue = isset($_POST['margin']) ? (int)$_POST['margin'] : 8;
$selectedFormat = normalizeOutputFormat((string)($_POST['format'] ?? 'png'));
$selectedFormatLabel = outputFormatLabel($selectedFormat);
$pageTitle = 'QR App Lite – Generator';
$activePage = 'generator';
$appVersion = QR_APP_VERSION;
require __DIR__ . '/app-header.php';
?>
  <main class="container app-container py-4">
    <div class="row justify-content-center">
      <div class="col-12 col-xl-10">
        <div class="app-page-header d-flex flex-column flex-md-row justify-content-between gap-3 align-items-md-end mb-4">
          <div>
            <h1 class="display-6 mb-1">QR-kode generator</h1>
            <?php if ($isPublicDemo): ?>
              <p class="text-secondary mb-0">Generér en QR-kode til direkte download uden lagring på serveren.</p>
            <?php else: ?>
              <p class="text-secondary mb-0">Lokal generering af QR-koder som billedfiler i <code><?= appE(QR_OUTPUT_DIR_NAME) ?>/</code>.</p>
            <?php endif; ?>
          </div>
          <div class="d-flex flex-wrap gap-2 align-self-start align-self-md-end">
            <a class="btn btn-outline-primary btn-sm" href="qr-scanner.php">Gå til scanner</a>
            <span class="badge text-bg-primary align-self-center"><?= appE(QR_APP_VERSION) ?></span>
          </div>
        </div>

        <?php if ($messages): ?>
          <div class="alert alert-success" role="alert">
            <ul class="mb-0">
              <?php foreach ($messages as $message): ?>
                <li><?= appE($message) ?></li>
              <?php endforeach; ?>
            </ul>
          </div>
        <?php endif; ?>

        <?php if ($errors): ?>
          <div class="alert alert-danger" role="alert">
            <h2 class="h5 alert-heading">Kontrollér følgende</h2>
            <ul class="mb-0">
              <?php foreach ($errors as $error): ?>
                <li><?= appE($error) ?></li>
              <?php endforeach; ?>
            </ul>
          </div>
        <?php endif; ?>

        <div class="row g-4">
          <div class="col-12 col-lg-8">
            <div class="card shadow-sm h-100">
              <div class="card-header bg-body-tertiary">
                <h2 class="h5 mb-0">Indstillinger</h2>
              </div>
              <div class="card-body">
                <form method="post" class="row g-3">
                  <div class="col-12">
                    <label for="text" class="form-label fw-semibold">Indhold</label>
                    <textarea id="text" name="text" rows="5" maxlength="<?= (int)QR_INPUT_MAX_LENGTH ?>" class="form-control" required placeholder="Indsæt tekst eller URL her"><?= appE($textValue) ?></textarea>
                    <div class="form-text">Maks. <?= (int)QR_INPUT_MAX_LENGTH ?> tegn. QR-koden kan indeholde almindelig tekst, URL, mailadresse, serienummer eller lignende.</div>
                  </div>

                  <div class="col-12 col-md-4">
                    <label for="size" class="form-label fw-semibold">Størrelse</label>
                    <div class="input-group">
                      <input id="size" type="number" name="size" min="100" max="2000" class="form-control" value="<?= (int)$sizeValue ?>">
                      <span class="input-group-text">px</span>
                    </div>
                  </div>

                  <div class="col-12 col-md-4">
                    <label for="margin" class="form-label fw-semibold">Margin</label>
                    <div class="input-group">
                      <input id="margin" type="number" name="margin" min="0" max="64" class="form-control" value="<?= (int)$marginValue ?>">
                      <span class="input-group-text">px</span>
                    </div>
                  </div>

                  <div class="col-12 col-md-4">
                    <label for="ec" class="form-label fw-semibold">Fejlkorrigering</label>
                    <select id="ec" name="ec" class="form-select">
                      <option value="L"<?= selected('L', $selectedEc) ?>>L - lav, ca. 7%</option>
                      <option value="M"<?= selected('M', $selectedEc) ?>>M - middel, ca. 15%</option>
                      <option value="Q"<?= selected('Q', $selectedEc) ?>>Q - kvartil, ca. 25%</option>
                      <option value="H"<?= selected('H', $selectedEc) ?>>H - høj, ca. 30%</option>
                    </select>
                  </div>

                  <div class="col-12 col-md-4">
                    <label for="format" class="form-label fw-semibold">Filformat</label>
                    <select id="format" name="format" class="form-select">
                      <option value="png"<?= selected('png', $selectedFormat) ?>>PNG</option>
                      <option value="jpeg"<?= selected('jpeg', $selectedFormat) ?>>JPEG</option>
                      <option value="tiff"<?= selected('tiff', $selectedFormat) ?>>TIFF</option>
                    </select>
                  </div>

                  <div class="col-12 d-flex flex-wrap gap-2 pt-2">
                    <button type="submit" class="btn btn-primary"><?= $isPublicDemo ? 'Generér til download' : 'Generér og gem lokalt' ?></button>
                    <button type="reset" class="btn btn-outline-secondary">Nulstil</button>
                  </div>
                </form>
              </div>
            </div>
          </div>

          <div class="col-12 col-lg-4">
            <aside class="card shadow-sm h-100">
              <div class="card-header bg-body-tertiary">
                <h2 class="h5 mb-0"><?= $isPublicDemo ? 'Demo-tilstand' : 'Lokal lagerstatus' ?></h2>
              </div>
              <div class="card-body">
                <?php if ($isPublicDemo): ?>
                  <p class="mb-0 small">Der oprettes ingen filer på serveren. Den genererede QR-kode findes kun midlertidigt på denne side og skal downloades med det samme.</p>
                <?php else: ?>
                  <dl class="row mb-0 small">
                    <dt class="col-6">Mappe</dt>
                    <dd class="col-6"><code><?= appE(QR_OUTPUT_DIR_NAME) ?>/</code></dd>
                    <dt class="col-6">QR-filer</dt>
                    <dd class="col-6"><?= (int)$outputStats['count'] ?></dd>
                    <dt class="col-6">Størrelse</dt>
                    <dd class="col-6"><?= appE(formatBytes((int)$outputStats['size_bytes'])) ?></dd>
                    <dt class="col-6">Auto-oprydning</dt>
                    <dd class="col-6"><?= (int)QR_OUTPUT_MAX_AGE_DAYS ?> dage / <?= (int)QR_OUTPUT_MAX_FILES ?> filer</dd>
                  </dl>
                <?php endif; ?>
              </div>
            </aside>
          </div>
        </div>

        <?php if ($inlineDataUri || $localPath): ?>
          <div class="row g-4 mt-1">
            <div class="col-12 col-lg-5">
              <div class="card shadow-sm h-100">
                <div class="card-header bg-body-tertiary">
                  <h2 class="h5 mb-0">Forhåndsvisning</h2>
                </div>
                <div class="card-body text-center">
                  <?php if ($inlineDataUri): ?>
                    <img class="qr-preview img-fluid border rounded bg-white p-2" src="<?= appE($inlineDataUri) ?>" alt="QR-kode">
                  <?php endif; ?>
                </div>
              </div>
            </div>

            <div class="col-12 col-lg-7">
              <div class="card shadow-sm h-100">
                <div class="card-header bg-body-tertiary">
                  <h2 class="h5 mb-0"><?= $isPublicDemo ? 'Download' : 'Fil' ?></h2>
                </div>
                <div class="card-body">
                  <?php if ($isPublicDemo && $inlineDataUri && $downloadFilename): ?>
                    <p class="mb-3">QR-koden er ikke gemt på serveren. Download den nu, hvis du vil beholde den.</p>
                    <a class="btn btn-success" href="<?= appE($inlineDataUri) ?>" download="<?= appE($downloadFilename) ?>">Download <?= appE($selectedFormatLabel) ?></a>
                  <?php elseif ($localPath): ?>
                    <p class="mb-3">QR-koden er gemt lokalt.</p>
                    <div class="d-flex flex-wrap gap-2 mb-3">
                      <a class="btn btn-success" href="<?= appE($localPath) ?>" download>Download <?= appE($selectedFormatLabel) ?></a>
                      <a class="btn btn-outline-secondary" href="<?= appE($localPath) ?>" target="_blank" rel="noopener">Åbn <?= appE($selectedFormatLabel) ?></a>
                    </div>
                    <div class="small text-secondary">Relativ sti:</div>
                    <code class="d-inline-block text-break bg-body-tertiary border rounded px-2 py-1"><?= appE($localPath) ?></code>
                  <?php endif; ?>
                </div>
              </div>
            </div>
          </div>
        <?php endif; ?>
      </div>
    </div>
  </main>

  <?php include __DIR__ . '/footer.php'; ?>
  <script src="js/bootstrap.bundle.min.js"></script>
</body>
</html>
