<?php
/**
 * POST /api/auth/register
 *
 * Body: name, email, password, confirm_password, phone (optional), country (optional)
 *
 * If OTP_SIGNUP_ENABLED=1: sends OTP, returns {status:'otp_sent'}
 *   payload (name + password hash) is stored encrypted in publisher_otp.payload
 *   so we don't create the user until OTP is verified.
 *
 * If OTP_SIGNUP_ENABLED=0: creates account immediately, logs in.
 */

declare(strict_types=1);
require_once dirname(__DIR__, 2) . '/config/bootstrap.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    jsonError('Method not allowed', 405);
}

// ───────────────────── Rate limit ─────────────────────
$ip = Logger::clientIp();
RateLimit::hit('signup:ip:' . $ip, 5, 3600, 'Too many signups from this IP. Try in 1 hour.');

// ───────────────────── Input ─────────────────────
$name     = Validator::clean((string)($_POST['name'] ?? ''), 120);
$email    = strtolower(Validator::clean((string)($_POST['email'] ?? ''), 190));
$password = (string)($_POST['password'] ?? '');
$confirm  = (string)($_POST['confirm_password'] ?? $password);
$phone    = Validator::clean((string)($_POST['phone'] ?? ''), 20);
$country  = Validator::clean((string)($_POST['country'] ?? 'India'), 80);
$cc       = Validator::clean((string)($_POST['country_code'] ?? '+91'), 5);

// ───────────────────── Validation ─────────────────────
if (!Validator::name($name))     jsonError('Please enter a valid name (2–120 chars).');
if (!Validator::email($email))   jsonError('Please enter a valid email address.');
if (!Validator::password($password)) jsonError(Validator::passwordError());
if ($password !== $confirm)      jsonError('Passwords do not match.');
if ($phone !== '' && !Validator::phone($phone)) jsonError('Please enter a valid phone number.');

// ───────────────────── Per-email rate limit ─────────────────────
RateLimit::hit('signup:email:' . $email, 3, 3600, 'Too many signup attempts for this email.');

// ───────────────────── Existing user check ─────────────────────
$pdo = db();
$stmt = $pdo->prepare("SELECT id, email_verified, status FROM publisher_user WHERE email = ? LIMIT 1");
$stmt->execute([$email]);
$existing = $stmt->fetch();

if ($existing) {
    if ((int)$existing['status'] === 0) {
        jsonError('This account has been blocked. Please contact support.');
    }
    if ((int)$existing['email_verified'] === 1) {
        jsonError('This email is already registered. Please log in.');
    }
    // unverified — allow re-trigger of OTP (will be handled below)
}

// ───────────────────── Branch on OTP toggle ─────────────────────
$otpEnabled = (int)env('OTP_SIGNUP_ENABLED', 1) === 1;
$pwdHash = password_hash($password, PASSWORD_ARGON2ID);

if (!$otpEnabled) {
    // ─── Direct create (OTP off) ───
    if ($existing) {
        // Update unverified row
        $pdo->prepare("
            UPDATE publisher_user
            SET name = ?, password_hash = ?, phone = ?, country = ?, country_code = ?,
                email_verified = 0
            WHERE id = ?
        ")->execute([$name, $pwdHash, $phone ?: null, $country, $cc, $existing['id']]);
        $publisherId = (int)$existing['id'];
    } else {
        $uuid = bin2hex(random_bytes(8)) . '-' . bin2hex(random_bytes(4)) . '-' . bin2hex(random_bytes(4)) . '-' . bin2hex(random_bytes(4)) . '-' . bin2hex(random_bytes(6));
        $pdo->prepare("
            INSERT INTO publisher_user
              (uuid, name, email, phone, country_code, country, password_hash, email_verified)
            VALUES (?, ?, ?, ?, ?, ?, ?, 0)
        ")->execute([$uuid, $name, $email, $phone ?: null, $cc, $country, $pwdHash]);
        $publisherId = (int)$pdo->lastInsertId();
    }

    Session::create($publisherId);
    Logger::audit($publisherId, 'signup_no_otp');

    jsonSuccess('Account created.', [
        'redirect'         => '/dashboard',
        'verify_required'  => false,
    ]);
}

// ─── OTP path ───
$otp     = str_pad((string)random_int(0, (int)str_repeat('9', (int)env('OTP_LENGTH', 6))), (int)env('OTP_LENGTH', 6), '0', STR_PAD_LEFT);
$otpHash = password_hash($otp, PASSWORD_BCRYPT);
$expiry  = time() + ((int)env('OTP_EXPIRY_MINUTES', 10) * 60);

// Look for existing unverified OTP for cooldown check
$check = $pdo->prepare("
    SELECT id, created_at FROM publisher_otp
    WHERE identifier = ? AND purpose = 'signup' AND verified = 0
    ORDER BY id DESC LIMIT 1
");
$check->execute([$email]);
$existingOtp = $check->fetch();

if ($existingOtp) {
    $age = time() - (int)$existingOtp['created_at'];
    $cooldown = (int)env('OTP_RESEND_COOLDOWN_SECONDS', 60);
    if ($age < $cooldown) {
        $wait = $cooldown - $age;
        jsonError("Please wait {$wait} seconds before requesting a new OTP.", 429);
    }
    // Invalidate older OTPs for this email/purpose
    $pdo->prepare("DELETE FROM publisher_otp WHERE identifier = ? AND purpose = 'signup' AND verified = 0")
        ->execute([$email]);
}

// Store the signup data in payload so verify-otp can finalize without re-asking
$payload = json_encode([
    'name'         => $name,
    'phone'        => $phone ?: null,
    'country'      => $country,
    'country_code' => $cc,
    'password_hash' => $pwdHash,
    'existing_id'  => $existing ? (int)$existing['id'] : null,
], JSON_UNESCAPED_UNICODE);

$pdo->prepare("
    INSERT INTO publisher_otp
      (identifier, identifier_type, purpose, otp_hash, expires_at, payload, created_at)
    VALUES (?, 'email', 'signup', ?, ?, ?, ?)
")->execute([$email, $otpHash, $expiry, $payload, time()]);

// Send mail
$sent = Mail::sendOtp($email, $otp, 'signup');
if (!$sent) {
    Logger::warning('OTP mail dispatch failed at signup', ['email' => $email]);
    // Don't reveal — still tell user to check inbox.
}

Logger::audit(null, 'signup_otp_sent', 'email', null, ['email' => $email]);

jsonSuccess('OTP sent to your email. Please check inbox & spam.', [
    'identifier'     => $email,
    'expires_in'     => (int)env('OTP_EXPIRY_MINUTES', 10) * 60,
    'redirect'       => '/verify-otp?purpose=signup&email=' . urlencode($email),
]);
