<?php

declare(strict_types=1);
// Ensure clean JSON responses (avoid HTML warnings/notices)
@ini_set('display_errors', '0');
error_reporting(E_ALL);
if (function_exists('ob_get_level') && ob_get_level() === 0) {
    ob_start();
}
require_once __DIR__ . '/../connect.php';
require_once __DIR__ . '/../config.php';

require_method('POST');
$data = get_input();
if (empty($data['first_name'] ?? '') && !empty($data['full_name'] ?? '')) {
    $full = trim((string)$data['full_name']);
    $firstTmp = $full;
    $lastTmp = '';
    $idx = strpos($full, ' ');
    if ($idx !== false && $idx > 0) {
        $firstTmp = trim(substr($full, 0, $idx));
        $lastTmp = trim(substr($full, $idx + 1));
    }
    $data['first_name'] = $firstTmp;
    if (!isset($data['last_name']) || $data['last_name'] === '') {
        $data['last_name'] = $lastTmp;
    }
}

$required = ['first_name', 'email', 'phone'];
require_fields($data, $required);

// Clean
$first = clean_string($data['first_name'] ?? '');
$last = clean_string($data['last_name'] ?? '');
$email = clean_string($data['email'] ?? '');
$phone = clean_string($data['phone'] ?? '');
$scfhs = clean_string($data['scfhs_id'] ?? 'NA');
$national = clean_string($data['national_id'] ?? '');
if ($national === '') {
    $national = '';
    for ($i = 0; $i < 12; $i++) { $national .= (string)random_int(0, 9); }
}
$spec = clean_string($data['speciality'] ?? 'NA');
$hosp = clean_string($data['hospital'] ?? 'NA');

// Validate
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    json_response(['error' => 'Invalid email address.'], 422);
}
if (!validate_phone($phone)) {
    json_response(['error' => 'Invalid phone number. Use + and digits only.'], 422);
}

// Uniqueness checks: email, phone, national_id must be unique
// Try DB first; if unavailable, fall back to file-based storage checks
$dups = [];
$checkedDb = false;
if (ENABLE_DB) {
    try {
        $pdoDup = pdo();
        ensure_table($pdoDup);
        $checkedDb = true;

        $q = $pdoDup->prepare('SELECT 1 FROM registrations WHERE email = :email LIMIT 1');
        $q->execute([':email' => $email]);
        if ($q->fetchColumn()) {
            $dups[] = 'email';
        }

        $q = $pdoDup->prepare('SELECT 1 FROM registrations WHERE phone = :phone LIMIT 1');
        $q->execute([':phone' => $phone]);
        if ($q->fetchColumn()) {
            $dups[] = 'phone';
        }


        if ($dups) {
            json_response(['error' => 'Duplicate fields: ' . implode(', ', $dups), 'duplicates' => $dups], 409);
        }
    } catch (Throwable $e) {
        // Continue to file-based checks
    }
}

if (!$checkedDb) {
    $regDir = __DIR__ . '/../storage/registrations/';
    if (is_dir($regDir)) {
        $target = [
            'email' => strtolower($email),
            'phone' => $phone,
            'national_id' => $national,
        ];
        foreach (glob($regDir . '*.json') as $file) {
            $rec = json_decode((string)@file_get_contents($file), true);
            if (!is_array($rec)) {
                continue;
            }
            if (!in_array('email', $dups, true) && isset($rec['email']) && strtolower((string)$rec['email']) === $target['email']) {
                $dups[] = 'email';
            }
            if (!in_array('phone', $dups, true) && isset($rec['phone']) && (string)$rec['phone'] === $target['phone']) {
                $dups[] = 'phone';
            }
            if (count($dups) === 2) {
                break;
            }
        }
    }
    if ($dups) {
        json_response(['error' => 'Duplicate fields: ' . implode(', ', $dups), 'duplicates' => $dups], 409);
    }
}

// Generate unique ID
$uuid = bin2hex(random_bytes(16));
$storedDb = false;

// Save to DB if enabled
$qrRelative = null;
try {
    if (ENABLE_DB) {
        $pdo = pdo();
        ensure_table($pdo);
        $stmt = $pdo->prepare('INSERT INTO registrations 
            (uuid, first_name, last_name, email, phone, scfhs_id, national_id, speciality, hospital, created_at)
            VALUES (:uuid, :first, :last, :email, :phone, :scfhs, :national, :spec, :hosp, :created)');
        $stmt->execute([
            ':uuid' => $uuid,
            ':first' => $first,
            ':last' => $last,
            ':email' => $email,
            ':phone' => $phone,
            ':scfhs' => $scfhs,
            ':national' => $national,
            ':spec' => $spec,
            ':hosp' => $hosp,
            ':created' => now(),
        ]);
        $storedDb = true;
    }
} catch (Throwable $e) {
    // If DB reports duplicate key, return 409 with conflicting fields
    $isDup = false;
    $dupFields = [];
    if ($e instanceof PDOException) {
        $info = $e->errorInfo ?? null; // [sqlstate, driver_code, message]
        $sqlState = is_array($info) && isset($info[0]) ? (string)$info[0] : (string)$e->getCode();
        $driverErr = is_array($info) && isset($info[1]) ? (int)$info[1] : 0;
        $msg = is_array($info) && isset($info[2]) ? (string)$info[2] : $e->getMessage();
        if ($sqlState === '23000' || $driverErr === 1062) {
            $isDup = true;
            $m = strtolower($msg);
            if (str_contains($m, 'uniq_email') || str_contains($m, "for key 'email'") || str_contains($m, 'for key \"email\"')) {
                $dupFields[] = 'email';
            }
            if (str_contains($m, 'uniq_phone') || str_contains($m, "for key 'phone'") || str_contains($m, 'for key \"phone\"')) {
                $dupFields[] = 'phone';
            }
            if (str_contains($m, 'uniq_national_id') || str_contains($m, "for key 'national_id'") || str_contains($m, 'for key \"national_id\"')) {
                $dupFields[] = 'national_id';
            }
            if (!$dupFields) {
                $dupFields = ['email', 'phone', 'national_id'];
            }
        }
    }
    if ($isDup) {
        json_response(['error' => 'Duplicate fields: ' . implode(', ', $dupFields), 'duplicates' => $dupFields], 409);
    }
    // Other DB errors: fall back to file-based storage
}

// Generate QR code image that links to the profile page for this registration
// Build absolute URL to profile.php?id=<uuid>
$scheme = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$script = $_SERVER['SCRIPT_NAME'] ?? '/api/submit.php';
$projectPath = rtrim(str_replace('\\', '/', dirname(dirname($script))), '/');
$profilePath = ($projectPath === '' ? '' : $projectPath) . '/profile.php?id=' . rawurlencode($uuid);
if ($profilePath === '' || $profilePath[0] !== '/') {
    $profilePath = '/' . ltrim($profilePath, '/');
}
$profileUrl = $scheme . '://' . $host . $profilePath;

// Encode the profile URL in the QR so scanning opens the profile page
$qrContent = $profileUrl;
$qrDir = __DIR__ . '/../storage/qrcodes/';
if (!is_dir($qrDir)) {
    @mkdir($qrDir, 0777, true);
}
$qrFile = $qrDir . $uuid . '.png';
$qrUrlService = 'https://api.qrserver.com/v1/create-qr-code/?size=' . QR_CODE_SIZE . 'x' . QR_CODE_SIZE . '&data=' . urlencode($qrContent);
$qrImage = @file_get_contents($qrUrlService);
if ($qrImage === false) {
    json_response(['error' => 'Failed to generate QR code. Please try again later.'], 500);
}
file_put_contents($qrFile, $qrImage);
$qrRelative = 'storage/qrcodes/' . $uuid . '.png';

// Update DB with QR path if possible
try {
    if (ENABLE_DB && $storedDb) {
        $pdo = $pdo ?? pdo();
        $upd = $pdo->prepare('UPDATE registrations SET qr_path = :qr WHERE uuid = :uuid');
        $upd->execute([':qr' => $qrRelative, ':uuid' => $uuid]);
    }
} catch (Throwable $e) { /* ignore */
}

// File-based storage fallback when DB disabled or failed
if (!$storedDb) {
    $regDir = __DIR__ . '/../storage/registrations/';
    if (!is_dir($regDir)) {
        @mkdir($regDir, 0777, true);
    }
    $record = [
        'uuid' => $uuid,
        'first_name' => $first,
        'last_name' => $last,
        'email' => $email,
        'phone' => $phone,
        'scfhs_id' => $scfhs,
        'national_id' => $national,
        'speciality' => $spec,
        'hospital' => $hosp,
        'qr_path' => $qrRelative,
        'created_at' => now(),
    ];
    @file_put_contents($regDir . $uuid . '.json', json_encode($record, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
}

// Send confirmation email
$emailSent = false;
$emailError = null;
if (ENABLE_EMAIL) {
    $subject = 'Registration Confirmation';
    // Generate a unique CID for embedding the QR inline
    $qrCid = 'qrimage-' . bin2hex(random_bytes(8)) . '@1CFD';
    // Use inline CID for QR image so it renders in the email body
    $html = email_template($first, $uuid, 'cid:' . $qrCid);
    $emailSent = send_email_with_attachment(
        $email,
        $subject,
        $html,
        $qrFile,
        'registration-qr-' . substr($uuid, 0, 8) . '.png',
        EMAIL_FROM,
        EMAIL_FROM_NAME,
        EMAIL_REPLY_TO,
        $qrCid,
        true
    );
    if (!$emailSent) {
        $emailError = 'Email could not be sent. Please verify email settings on the server.';
    }
}

json_response([
    'success' => true,
    'id' => $uuid,
    'qr_url' => $qrRelative,
    'profile_url' => $profileUrl,
    'storage' => $storedDb ? 'db' : 'file',
    'email_sent' => $emailSent,
    'email_error' => $emailError,
]);

// ========== Helpers ==========
function ensure_table(PDO $pdo): void
{
    $sql = "CREATE TABLE IF NOT EXISTS registrations (
        id INT AUTO_INCREMENT PRIMARY KEY,
        uuid VARCHAR(64) NOT NULL UNIQUE,
        first_name VARCHAR(100) NOT NULL,
        last_name VARCHAR(100) NOT NULL,
        email VARCHAR(255) NOT NULL,
        phone VARCHAR(20) NOT NULL,
        scfhs_id VARCHAR(50) NOT NULL,
        national_id VARCHAR(50) NOT NULL,
        speciality VARCHAR(150) NOT NULL,
        hospital VARCHAR(150) NOT NULL,
        qr_path VARCHAR(255) NULL,
        created_at DATETIME NOT NULL,
        UNIQUE KEY uniq_email (email),
        UNIQUE KEY uniq_phone (phone),
        UNIQUE KEY uniq_national_id (national_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    $pdo->exec($sql);
    // For existing tables created earlier without unique keys, attempt to add them idempotently
    try {
        $pdo->exec('ALTER TABLE registrations ADD UNIQUE KEY uniq_email (email)');
    } catch (Throwable $e) { /* ignore */
    }
    try {
        $pdo->exec('ALTER TABLE registrations ADD UNIQUE KEY uniq_phone (phone)');
    } catch (Throwable $e) { /* ignore */
    }
    try {
        $pdo->exec('ALTER TABLE registrations ADD UNIQUE KEY uniq_national_id (national_id)');
    } catch (Throwable $e) { /* ignore */
    }
}

function email_template(string $first, string $uuid, ?string $qrRelative): string
{
    $accent = ACCENT_COLOR;
    $greeting = htmlspecialchars($first, ENT_QUOTES, 'UTF-8');
    $qrSrc = htmlspecialchars($qrRelative ?? '', ENT_QUOTES, 'UTF-8');
    return <<<HTML
<!doctype html>
<html>
  <body style="margin:0;padding:0;font-family:Arial,Helvetica,sans-serif;background:#ffffff;color:#000000;">
    <div style="max-width:640px;margin:0 auto;padding:24px;">
      <h2 style="margin:0 0 12px 0;font-weight:700;">Registration Confirmed</h2>
      <p style="margin:0 0 16px 0;">Dear {$greeting},</p>
      <p style="margin:0 0 16px 0;">Thank you for registering! We’re truly excited to have you with us and can’t wait to welcome you at the event.</p>
      <p style="margin:0 0 16px 0;">Your participation means a lot to us, and we look forward to sharing an inspiring, engaging, and memorable experience together.</p>
      <p style="margin:0 0 24px 0;">See you soon!</p>
      <div style="margin:24px 0;padding:16px;border:2px solid {$accent};border-radius:8px;text-align:center;">
        <div style="font-weight:700;margin-bottom:8px;">Your QR Code</div>
        <img src="{$qrSrc}" alt="Your registration QR code" style="max-width:320px;width:100%;height:auto;" />
      </div>
      <p style="margin:24px 0 0 0;color:#666;font-size:12px;">If you did not request this, you can ignore this email.</p>
    </div>
  </body>
</html>
HTML;
}

function send_email_with_attachment(
    string $to,
    string $subject,
    string $html,
    string $attachmentPath,
    string $attachmentName,
    string $fromEmail,
    string $fromName,
    ?string $replyTo = null,
    ?string $inlineCid = null,
    bool $attachDownload = false
): bool {
    $boundaryRel = '=_' . bin2hex(random_bytes(12));
    $boundaryAlt = '=_' . bin2hex(random_bytes(12));

    // Common headers (without To/Subject for mail())
    $headersCommon = [];
    $headersCommon[] = 'MIME-Version: 1.0';
    $headersCommon[] = 'From: ' . encode_header($fromName) . ' <' . $fromEmail . '>';
    if ($replyTo) {
        $headersCommon[] = 'Reply-To: ' . $replyTo;
    }
    $headersCommon[] = 'Date: ' . date('r');
    $headersCommon[] = 'Content-Type: multipart/related; boundary="' . $boundaryRel . '"';

    $text = strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $html));

    $body = '';
    $body .= '--' . $boundaryRel . "\r\n";
    $body .= 'Content-Type: multipart/alternative; boundary="' . $boundaryAlt . '"' . "\r\n\r\n";

    // Plain text
    $body .= '--' . $boundaryAlt . "\r\n";
    $body .= 'Content-Type: text/plain; charset=UTF-8' . "\r\n";
    $body .= 'Content-Transfer-Encoding: 7bit' . "\r\n\r\n";
    $body .= $text . "\r\n\r\n";

    // HTML
    $body .= '--' . $boundaryAlt . "\r\n";
    $body .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
    $body .= 'Content-Transfer-Encoding: 7bit' . "\r\n\r\n";
    $body .= $html . "\r\n\r\n";
    $body .= '--' . $boundaryAlt . "--\r\n";

    $fileData = null;
    if (is_readable($attachmentPath)) {
        $fileData = chunk_split(base64_encode((string)file_get_contents($attachmentPath)));
    }

    // Inline QR image via CID that matches template
    if ($inlineCid !== null && $fileData !== null) {
        $body .= '--' . $boundaryRel . "\r\n";
        $body .= 'Content-Type: image/png; name="' . addslashes($attachmentName) . '"' . "\r\n";
        $body .= 'Content-Transfer-Encoding: base64' . "\r\n";
        $body .= 'Content-ID: <' . $inlineCid . '>' . "\r\n";
        $body .= 'X-Attachment-Id: ' . $inlineCid . "\r\n";
        $body .= 'Content-Disposition: inline; filename="' . addslashes($attachmentName) . '"' . "\r\n\r\n";
        $body .= $fileData . "\r\n";
    }

    // Optional downloadable attachment copy of the QR
    if ($attachDownload && $fileData !== null) {
        $body .= '--' . $boundaryRel . "\r\n";
        $body .= 'Content-Type: image/png; name="' . addslashes($attachmentName) . '"' . "\r\n";
        $body .= 'Content-Transfer-Encoding: base64' . "\r\n";
        $body .= 'Content-Disposition: attachment; filename="' . addslashes($attachmentName) . '"' . "\r\n\r\n";
        $body .= $fileData . "\r\n";
    }

    $body .= '--' . $boundaryRel . "--\r\n";

    // Try SMTP if configured
    $useSmtp = defined('SMTP_HOST') && defined('SMTP_USERNAME') && defined('SMTP_PASSWORD')
        && SMTP_HOST !== '' && SMTP_USERNAME !== '' && SMTP_PASSWORD !== '';
    if ($useSmtp) {
        $headersForSmtp = 'To: ' . $to . "\r\n" . 'Subject: ' . encode_header($subject) . "\r\n" . implode("\r\n", $headersCommon);
        if (smtp_send($to, $fromEmail, $headersForSmtp, $body)) {
            return true;
        }
        // If SMTP fails, fall back to mail()
    }

    return mail($to, encode_header($subject), $body, implode("\r\n", $headersCommon));
}

function encode_header(string $str): string
{
    if (preg_match('/[^\x20-\x7E]/', $str)) {
        return '=?UTF-8?B?' . base64_encode($str) . '?=';
    }
    return $str;
}

/**
 * Minimal SMTP client to send email via Gmail or other SMTP servers.
 * Supports SSL (implicit TLS, port 465) and STARTTLS (port 587).
 */
function smtp_send(string $to, string $from, string $headers, string $body): bool
{
    $host = (string)SMTP_HOST;
    $port = (int)SMTP_PORT;
    $user = (string)SMTP_USERNAME;
    $pass = (string)SMTP_PASSWORD;
    $enc  = strtolower((string)SMTP_ENCRYPTION);

    $remote = $host;
    if ($enc === 'ssl') {
        $remote = 'ssl://' . $host;
    }

    $errno = 0;
    $errstr = '';
    $fp = @fsockopen($remote, $port, $errno, $errstr, 20);
    if (!$fp) {
        return false;
    }
    stream_set_timeout($fp, 20);

    $code = smtp_read_code($fp);
    if ($code !== 220) {
        fclose($fp);
        return false;
    }

    if (!smtp_cmd_expect($fp, 'EHLO localhost', 250)) {
        // Some servers may require HELO
        if (!smtp_cmd_expect($fp, 'HELO localhost', 250)) {
            fclose($fp);
            return false;
        }
    }

    if ($enc === 'tls') {
        if (!smtp_cmd_expect($fp, 'STARTTLS', 220)) {
            fclose($fp);
            return false;
        }
        if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
            fclose($fp);
            return false;
        }
        if (!smtp_cmd_expect($fp, 'EHLO localhost', 250)) {
            fclose($fp);
            return false;
        }
    }

    // AUTH LOGIN
    if (!smtp_cmd_expect($fp, 'AUTH LOGIN', 334)) {
        fclose($fp);
        return false;
    }
    if (!smtp_cmd_expect($fp, base64_encode($user), 334)) {
        fclose($fp);
        return false;
    }
    if (!smtp_cmd_expect($fp, base64_encode($pass), 235)) {
        fclose($fp);
        return false;
    }

    if (!smtp_cmd_expect($fp, 'MAIL FROM:<' . $from . '>', 250)) {
        fclose($fp);
        return false;
    }
    if (!smtp_cmd_expect($fp, 'RCPT TO:<' . $to . '>', [250, 251])) {
        fclose($fp);
        return false;
    }
    if (!smtp_cmd_expect($fp, 'DATA', 354)) {
        fclose($fp);
        return false;
    }

    // Build data with proper dot-stuffing
    $data = $headers . "\r\n\r\n" . $body;
    $data = str_replace(["\r\n.\r\n", "\n.\n"], ["\r\n..\r\n", "\n..\n"], $data);
    fwrite($fp, $data . "\r\n.\r\n");
    $code = smtp_read_code($fp);
    $ok = ($code === 250);
    smtp_cmd_expect($fp, 'QUIT', 221);
    fclose($fp);
    return $ok;
}

function smtp_cmd_expect($fp, string $cmd, int|array $expected): bool
{
    fwrite($fp, $cmd . "\r\n");
    $code = smtp_read_code($fp);
    if (is_array($expected)) {
        return in_array($code, $expected, true);
    }
    return $code === $expected;
}

function smtp_read_code($fp): int
{
    $line = '';
    $code = 0;
    while (!feof($fp)) {
        $l = fgets($fp, 515);
        if ($l === false) {
            break;
        }
        $line = $l;
        if (preg_match('/^(\d{3})([ -])/', $line, $m)) {
            $code = (int)$m[1];
            if ($m[2] === ' ') {
                break;
            } // last line of response
        }
    }
    return $code;
}
