<?php
// ─────────────────────────────────────────────────────────────
//  api/auth.php — Customer auth API
//  Actions: register | login | logout | forgot | reset
//           verify-email | me | update-profile | resend-verify
//           cancel-appointment
// ─────────────────────────────────────────────────────────────
require_once dirname(__DIR__) . '/lib.php';
cors();

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }

function normalize_phone(string $phone): string {
    $norm = preg_replace('/[^0-9\+]/', '', trim($phone));
    return substr((string)$norm, 0, 24);
}
function validate_member_profile_fields(array $b, bool $required): array {
    $name = trim((string)($b['name'] ?? ''));
    $phone = normalize_phone((string)($b['phone'] ?? ''));
    $dob = trim((string)($b['dob'] ?? ''));
    $gender = strtolower(trim((string)($b['gender'] ?? '')));
    $addressLine1 = trim((string)($b['address_line1'] ?? ''));
    $city = trim((string)($b['city'] ?? ''));
    $country = trim((string)($b['country'] ?? ''));
    $emergencyName = trim((string)($b['emergency_contact_name'] ?? ''));
    $emergencyPhone = normalize_phone((string)($b['emergency_contact_phone'] ?? ''));
    if ($required) {
        foreach ([
            'name' => $name, 'phone' => $phone, 'dob' => $dob, 'gender' => $gender,
            'address_line1' => $addressLine1, 'city' => $city, 'country' => $country,
            'emergency_contact_name' => $emergencyName, 'emergency_contact_phone' => $emergencyPhone
        ] as $k => $v) {
            if ($v === '') json_out(['ok'=>false,'error'=>"{$k} is required"], 422);
        }
    }
    if ($name !== '' && mb_strlen($name) > 120) json_out(['ok'=>false,'error'=>'Name is too long'], 422);
    if ($phone !== '' && !preg_match('/^\+?[0-9]{7,20}$/', $phone)) json_out(['ok'=>false,'error'=>'Invalid phone format'], 422);
    if ($emergencyPhone !== '' && !preg_match('/^\+?[0-9]{7,20}$/', $emergencyPhone)) json_out(['ok'=>false,'error'=>'Invalid emergency contact phone format'], 422);
    if ($dob !== '') {
        $d = DateTime::createFromFormat('Y-m-d', $dob);
        if (!$d || $d->format('Y-m-d') !== $dob) json_out(['ok'=>false,'error'=>'Invalid DOB format (YYYY-MM-DD)'], 422);
    }
    if ($gender !== '' && !in_array($gender, ['male','female','other'], true)) json_out(['ok'=>false,'error'=>'Invalid gender'], 422);
    if ($addressLine1 !== '' && mb_strlen($addressLine1) > 180) json_out(['ok'=>false,'error'=>'Address too long'], 422);
    if ($city !== '' && mb_strlen($city) > 120) json_out(['ok'=>false,'error'=>'City too long'], 422);
    if ($country !== '' && mb_strlen($country) > 120) json_out(['ok'=>false,'error'=>'Country too long'], 422);
    if ($emergencyName !== '' && mb_strlen($emergencyName) > 120) json_out(['ok'=>false,'error'=>'Emergency contact name too long'], 422);
    return [$name, $phone, $dob, $gender, $addressLine1, $city, $country, $emergencyName, $emergencyPhone];
}

$body   = json_decode(file_get_contents('php://input'), true) ?? [];
$action = $body['action'] ?? ($_GET['action'] ?? '');

match ($action) {
    'register'           => auth_register($body),
    'login'              => auth_login($body),
    'logout'             => auth_logout(),
    'forgot'             => auth_forgot($body),
    'reset'              => auth_reset($body),
    'verify-email'       => auth_verify_email($body),
    'me'                 => auth_me(),
    'update-profile'     => auth_update_profile($body),
    'resend-verify'      => auth_resend_verify(),
    'cancel-appointment'    => auth_cancel_appt($body),
    'reschedule-appointment'=> auth_reschedule_appt($body),
    default                 => json_out(['ok' => false, 'error' => 'Unknown action'], 400),
};

// ─────────────────────────────────────────────────────────────
//  Shared email sender
// ─────────────────────────────────────────────────────────────
function auth_send_email(string $to, string $toName, string $subject,
                         string $heading, string $bodyText,
                         string $btnUrl, string $btnLabel, string $footnote): void {
    $app = APP_NAME;
    $html = <<<HTML
<!DOCTYPE html><html><head><meta charset="UTF-8"></head>
<body style="margin:0;padding:0;background:#f4f5f7;font-family:'DM Sans',Arial,sans-serif">
<table width="100%" cellpadding="0" cellspacing="0"><tr><td align="center" style="padding:40px 16px">
<table width="520" cellpadding="0" cellspacing="0" style="background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,.08)">
  <tr><td style="background:linear-gradient(135deg,#f5a623,#b87800);padding:28px 32px">
    <p style="margin:0 0 4px;color:rgba(255,255,255,.7);font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase">$app</p>
    <h1 style="margin:0;color:#fff;font-size:22px;font-weight:800">$heading</h1>
  </td></tr>
  <tr><td style="padding:32px">
    <p style="margin:0 0 24px;font-size:15px;color:#374151;line-height:1.6">$bodyText</p>
    <a href="$btnUrl" style="display:inline-block;background:#e09500;color:#fff;font-size:14px;font-weight:700;padding:14px 28px;border-radius:10px;text-decoration:none">$btnLabel</a>
    <p style="margin:24px 0 0;font-size:12px;color:#9ca3af">$footnote</p>
  </td></tr>
  <tr><td style="padding:16px 32px;border-top:1px solid #f1f5f9">
    <p style="margin:0;font-size:11px;color:#9ca3af">$app &middot; Sent automatically &middot; Do not reply</p>
  </td></tr>
</table>
</td></tr></table></body></html>
HTML;
$plain = strip_tags(str_replace(['<br>','</p>'], "\n", $html));
try { send_mail($to, $toName, $subject, $html, $plain); }
catch (Throwable $e) { error_log("auth email error: " . $e->getMessage()); }
}

// ─────────────────────────────────────────────────────────────
//  Register
// ─────────────────────────────────────────────────────────────
function auth_register(array $b): void {
    $email    = strtolower(trim($b['email'] ?? ''));
    $password = $b['password'] ?? '';
    $name     = trim($b['name'] ?? '');

    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) json_out(['ok'=>false,'error'=>'Invalid email address'], 422);
    if (strlen($password) < 8)  json_out(['ok'=>false,'error'=>'Password must be at least 8 characters'], 422);
    if (empty($name))           json_out(['ok'=>false,'error'=>'Name is required'], 422);

    $pdo = db();
    $chk = $pdo->prepare('SELECT id FROM bk_users WHERE email = ?');
    $chk->execute([$email]);
    if ($chk->fetch()) json_out(['ok'=>false,'error'=>'An account with this email already exists'], 409);

    $hash  = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
    $token = bin2hex(random_bytes(32));

    $pdo->prepare('INSERT INTO bk_users (email, password_hash, reset_token, reset_token_expires)
                   VALUES (?, ?, ?, DATE_ADD(NOW(), INTERVAL 24 HOUR))')
        ->execute([$email, $hash, $token]);
    $userId = (int)$pdo->lastInsertId();

    // Link or create bk_customers record (migration-safe)
    $cust = $pdo->prepare('SELECT id FROM bk_customers WHERE email = ?');
    $cust->execute([$email]);
    $customer = $cust->fetch();
    if ($customer) {
        $pdo->prepare('UPDATE bk_customers SET user_id = ? WHERE id = ?')->execute([$userId, $customer['id']]);
    } else {
        $pdo->prepare('INSERT INTO bk_customers (user_id, email, name) VALUES (?, ?, ?)')->execute([$userId, $email, $name]);
    }

    $verifyUrl = rtrim(APP_URL, '/') . '/verify-email.php?token=' . $token;
    auth_send_email($email, $name, "Verify your " . APP_NAME . " account",
        "Verify your email",
        "Welcome to " . APP_NAME . ", {$name}! Click below to verify your email address and activate your account.",
        $verifyUrl, "Verify Email Address",
        "Expires in 24 hours. If you didn't create this account, ignore this email."
    );
    json_out(['ok' => true, 'message' => 'Account created — check your email to verify.']);
}

// ─────────────────────────────────────────────────────────────
//  Login
// ─────────────────────────────────────────────────────────────
function auth_login(array $b): void {
    $email    = strtolower(trim($b['email'] ?? ''));
    $password = $b['password'] ?? '';
    $remember = !empty($b['remember']);

    if (empty($email) || empty($password)) json_out(['ok'=>false,'error'=>'Email and password are required'], 422);

    $pdo  = db();
    $stmt = $pdo->prepare('SELECT id, email, password_hash, email_verified_at FROM bk_users WHERE email = ?');
    $stmt->execute([$email]);
    $user = $stmt->fetch();

    if (!$user || !password_verify($password, $user['password_hash'])) {
        json_out(['ok'=>false,'error'=>'Invalid email or password'], 401);
    }

    session_start_safe();
    session_regenerate_id(true);
    $_SESSION['bk_user_id']    = (int)$user['id'];
    $_SESSION['bk_user_email'] = $user['email'];
    $_SESSION['bk_user_time']  = time();

    if ($remember) {
        $remToken = bin2hex(random_bytes(32));
        $pdo->prepare('UPDATE bk_users SET remember_token = ? WHERE id = ?')->execute([$remToken, $user['id']]);
        setcookie('bk_remember', $remToken, [
            'expires' => time() + 86400 * 30, 'path' => '/',
            'httponly' => true, 'samesite' => 'Lax', 'secure' => isset($_SERVER['HTTPS']),
        ]);
    }
    json_out(['ok' => true, 'verified' => !empty($user['email_verified_at'])]);
}

// ─────────────────────────────────────────────────────────────
//  Logout
// ─────────────────────────────────────────────────────────────
function auth_logout(): void {
    session_start_safe();
    $uid = $_SESSION['bk_user_id'] ?? null;
    if ($uid) db()->prepare('UPDATE bk_users SET remember_token = NULL WHERE id = ?')->execute([$uid]);
    session_destroy();
    setcookie('bk_remember', '', ['expires'=>time()-3600,'path'=>'/','httponly'=>true,'samesite'=>'Lax']);
    json_out(['ok' => true]);
}

// ─────────────────────────────────────────────────────────────
//  Forgot password
// ─────────────────────────────────────────────────────────────
function auth_forgot(array $b): void {
    $email = strtolower(trim($b['email'] ?? ''));
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) json_out(['ok'=>false,'error'=>'Invalid email address'], 422);

    $pdo  = db();
    $stmt = $pdo->prepare('SELECT id FROM bk_users WHERE email = ?');
    $stmt->execute([$email]);
    $user = $stmt->fetch();

    if ($user) {
        $token   = bin2hex(random_bytes(32));
        $expires = date('Y-m-d H:i:s', time() + 3600);
        $pdo->prepare('UPDATE bk_users SET reset_token = ?, reset_token_expires = ? WHERE id = ?')
            ->execute([$token, $expires, $user['id']]);
        $resetUrl = rtrim(APP_URL, '/') . '/reset-password.php?token=' . $token;
        auth_send_email($email, $email, "Reset your " . APP_NAME . " password",
            "Reset your password",
            "We received a request to reset the password for this account. Click below to choose a new one.",
            $resetUrl, "Reset Password",
            "Expires in 1 hour. If you didn't request this, no action is needed."
        );
    }
    json_out(['ok' => true, 'message' => "If that email is registered, you'll receive a reset link shortly."]);
}

// ─────────────────────────────────────────────────────────────
//  Reset password
// ─────────────────────────────────────────────────────────────
function auth_reset(array $b): void {
    $token    = $b['token'] ?? '';
    $password = $b['password'] ?? '';
    if (empty($token))         json_out(['ok'=>false,'error'=>'Missing token'], 422);
    if (strlen($password) < 8) json_out(['ok'=>false,'error'=>'Password must be at least 8 characters'], 422);

    $pdo  = db();
    $stmt = $pdo->prepare('SELECT id FROM bk_users WHERE reset_token = ? AND reset_token_expires > NOW()');
    $stmt->execute([$token]);
    $user = $stmt->fetch();
    if (!$user) json_out(['ok'=>false,'error'=>'This reset link is invalid or has expired'], 400);

    $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
    $pdo->prepare('UPDATE bk_users SET password_hash = ?, reset_token = NULL, reset_token_expires = NULL, updated_at = NOW() WHERE id = ?')
        ->execute([$hash, $user['id']]);
    json_out(['ok' => true, 'message' => 'Password updated — you can now sign in.']);
}

// ─────────────────────────────────────────────────────────────
//  Verify email
// ─────────────────────────────────────────────────────────────
function auth_verify_email(array $b): void {
    $token = $b['token'] ?? $_GET['token'] ?? '';
    if (empty($token)) json_out(['ok'=>false,'error'=>'Missing token'], 422);

    $pdo  = db();
    $stmt = $pdo->prepare('SELECT id, email_verified_at FROM bk_users WHERE reset_token = ? AND reset_token_expires > NOW()');
    $stmt->execute([$token]);
    $user = $stmt->fetch();
    if (!$user) json_out(['ok'=>false,'error'=>'This verification link is invalid or has expired'], 400);
    if ($user['email_verified_at']) json_out(['ok'=>true,'already'=>true,'message'=>'Email already verified']);

    $pdo->prepare('UPDATE bk_users SET email_verified_at = NOW(), reset_token = NULL, reset_token_expires = NULL WHERE id = ?')
        ->execute([$user['id']]);
    json_out(['ok' => true, 'message' => 'Email verified — you can now sign in.']);
}

// ─────────────────────────────────────────────────────────────
//  Me (session status)
// ─────────────────────────────────────────────────────────────
function auth_me(): void {
    if (!customer_logged_in()) json_out(['ok'=>false,'authenticated'=>false]);

    $stmt = db()->prepare('
        SELECT u.id, u.email, u.email_verified_at, u.created_at AS member_since,
               c.id AS customer_id, c.name, c.phone, c.dob, c.gender, c.address_line1,
               c.city, c.country, c.emergency_contact_name, c.emergency_contact_phone
        FROM bk_users u
        LEFT JOIN bk_customers c ON c.user_id = u.id
        WHERE u.id = ?
    ');
    $stmt->execute([$_SESSION['bk_user_id']]);
    $user = $stmt->fetch();
    if (!$user) { session_destroy(); json_out(['ok'=>false,'authenticated'=>false]); }

    $profileComplete = !empty($user['name'])
        && !empty($user['phone'])
        && !empty($user['dob'])
        && !empty($user['gender'])
        && !empty($user['address_line1'])
        && !empty($user['city'])
        && !empty($user['country'])
        && !empty($user['emergency_contact_name'])
        && !empty($user['emergency_contact_phone']);

    json_out(['ok'=>true,'authenticated'=>true,'user'=>[
        'id'          => (int)$user['id'],
        'customer_id' => (int)($user['customer_id'] ?? 0),
        'email'       => $user['email'],
        'name'        => $user['name'] ?? '',
        'phone'       => $user['phone'] ?? '',
        'dob'         => $user['dob'] ?? null,
        'gender'      => $user['gender'] ?? null,
        'address_line1' => $user['address_line1'] ?? '',
        'city'        => $user['city'] ?? '',
        'country'     => $user['country'] ?? '',
        'emergency_contact_name' => $user['emergency_contact_name'] ?? '',
        'emergency_contact_phone' => $user['emergency_contact_phone'] ?? '',
        'profile_complete' => $profileComplete,
        'verified'    => !empty($user['email_verified_at']),
        'member_since'=> $user['member_since'],
    ]]);
}

// ─────────────────────────────────────────────────────────────
//  Update profile
// ─────────────────────────────────────────────────────────────
function auth_update_profile(array $b): void {
    if (!customer_logged_in()) json_out(['ok'=>false,'error'=>'Not authenticated'], 401);
    $userId = (int)$_SESSION['bk_user_id'];

    $requireComplete = !empty($b['require_complete']);
    [$name, $phone, $dob, $gender, $addressLine1, $city, $country, $emergencyName, $emergencyPhone] =
        validate_member_profile_fields($b, $requireComplete);
    $newPassword = $b['new_password'] ?? '';
    $curPassword = $b['current_password'] ?? '';

    if (empty($name)) json_out(['ok'=>false,'error'=>'Name is required'], 422);

    $pdo = db();
    $pdo->prepare('UPDATE bk_customers SET name = ?, phone = ?, dob = ?, gender = ?, address_line1 = ?, city = ?, country = ?, emergency_contact_name = ?, emergency_contact_phone = ? WHERE user_id = ?')
        ->execute([
            $name,
            $phone ?: null,
            $dob ?: null,
            $gender ?: null,
            $addressLine1 ?: null,
            $city ?: null,
            $country ?: null,
            $emergencyName ?: null,
            $emergencyPhone ?: null,
            $userId
        ]);

    if ($newPassword !== '') {
        if (strlen($newPassword) < 8) json_out(['ok'=>false,'error'=>'New password must be at least 8 characters'], 422);
        $row = $pdo->prepare('SELECT password_hash FROM bk_users WHERE id = ?');
        $row->execute([$userId]);
        $row = $row->fetch();
        if (!$row || !password_verify($curPassword, $row['password_hash'])) {
            json_out(['ok'=>false,'error'=>'Current password is incorrect'], 403);
        }
        $pdo->prepare('UPDATE bk_users SET password_hash = ?, updated_at = NOW() WHERE id = ?')
            ->execute([password_hash($newPassword, PASSWORD_BCRYPT, ['cost'=>12]), $userId]);
    }
    json_out(['ok' => true, 'message' => 'Profile updated.']);
}

// ─────────────────────────────────────────────────────────────
//  Resend verification email
// ─────────────────────────────────────────────────────────────
function auth_resend_verify(): void {
    if (!customer_logged_in()) json_out(['ok'=>false,'error'=>'Not authenticated'], 401);

    $pdo  = db();
    $stmt = $pdo->prepare('SELECT id, email, email_verified_at FROM bk_users WHERE id = ?');
    $stmt->execute([$_SESSION['bk_user_id']]);
    $user = $stmt->fetch();
    if (!$user)                     json_out(['ok'=>false,'error'=>'User not found'], 404);
    if ($user['email_verified_at']) json_out(['ok'=>false,'error'=>'Email is already verified'], 400);

    $token = bin2hex(random_bytes(32));
    $pdo->prepare('UPDATE bk_users SET reset_token = ?, reset_token_expires = DATE_ADD(NOW(), INTERVAL 24 HOUR) WHERE id = ?')
        ->execute([$token, $user['id']]);

    $verifyUrl = rtrim(APP_URL, '/') . '/verify-email.php?token=' . $token;
    auth_send_email($user['email'], $user['email'], "Verify your " . APP_NAME . " email",
        "Verify your email", "Click the button below to verify your email address.",
        $verifyUrl, "Verify Email Address", "Expires in 24 hours."
    );
    json_out(['ok' => true, 'message' => 'Verification email sent.']);
}

// ─────────────────────────────────────────────────────────────
//  Cancel appointment (customer self-serve)
// ─────────────────────────────────────────────────────────────
function auth_cancel_appt(array $b): void {
    if (!customer_logged_in()) json_out(['ok'=>false,'error'=>'Not authenticated'], 401);
    $userId = (int)$_SESSION['bk_user_id'];
    $apptId = (int)($b['id'] ?? 0);
    if (!$apptId) json_out(['ok'=>false,'error'=>'Missing appointment id'], 422);

    $pdo  = db();
    $stmt = $pdo->prepare('
        SELECT a.id, a.status, a.start_datetime
        FROM bk_appointments a
        JOIN bk_customers c ON c.id = a.customer_id
        WHERE a.id = ? AND c.user_id = ?
    ');
    $stmt->execute([$apptId, $userId]);
    $appt = $stmt->fetch();

    if (!$appt)                          json_out(['ok'=>false,'error'=>'Appointment not found'], 404);
    if ($appt['status'] === 'cancelled') json_out(['ok'=>false,'error'=>'Already cancelled'], 400);
    if (strtotime($appt['start_datetime']) < time()) json_out(['ok'=>false,'error'=>'Cannot cancel a past appointment'], 400);

    $pdo->prepare('UPDATE bk_appointments SET status = "cancelled" WHERE id = ?')->execute([$apptId]);
    json_out(['ok' => true, 'message' => 'Appointment cancelled.']);
}

function auth_reschedule_appt(array $b): void {
    if (!customer_logged_in()) json_out(['ok'=>false,'error'=>'Not authenticated'], 401);
    $userId      = (int)$_SESSION['bk_user_id'];
    $apptId      = (int)($b['id'] ?? 0);
    $newDatetime = trim($b['datetime'] ?? '');

    if (!$apptId)      json_out(['ok'=>false,'error'=>'Missing appointment id'], 422);
    if (!$newDatetime) json_out(['ok'=>false,'error'=>'Missing datetime'], 422);

    // Validate datetime format
    $dtObj = DateTime::createFromFormat('Y-m-d H:i:s', $newDatetime)
          ?: DateTime::createFromFormat('Y-m-d H:i', $newDatetime);
    if (!$dtObj) json_out(['ok'=>false,'error'=>'Invalid datetime format. Use Y-m-d H:i'], 422);
    $newDatetime = $dtObj->format('Y-m-d H:i:s');
    if (strtotime($newDatetime) <= time()) json_out(['ok'=>false,'error'=>'New time must be in the future'], 400);

    $pdo  = db();

    // Verify appointment belongs to this user and is reschedulable
    $stmt = $pdo->prepare('
        SELECT a.id, a.status, a.start_datetime, a.provider_id, a.service_id
        FROM bk_appointments a
        JOIN bk_customers c ON c.id = a.customer_id
        WHERE a.id = ? AND c.user_id = ?
    ');
    $stmt->execute([$apptId, $userId]);
    $appt = $stmt->fetch();

    if (!$appt) json_out(['ok'=>false,'error'=>'Appointment not found'], 404);
    if (in_array($appt['status'], ['cancelled','no_show','completed'])) {
        json_out(['ok'=>false,'error'=>'Cannot reschedule a ' . $appt['status'] . ' appointment'], 400);
    }
    if (strtotime($appt['start_datetime']) < time()) {
        json_out(['ok'=>false,'error'=>'Cannot reschedule a past appointment'], 400);
    }

    // Get service duration for new end_datetime
    $svcRow = $pdo->prepare('SELECT duration_min FROM bk_services WHERE id=?');
    $svcRow->execute([$appt['service_id']]);
    $svc = $svcRow->fetch();
    if (!$svc) json_out(['ok'=>false,'error'=>'Service not found'], 500);
    $newEndDatetime = date('Y-m-d H:i:s', strtotime($newDatetime) + $svc['duration_min'] * 60);

    // Race-condition check inside transaction
    require_once dirname(__DIR__) . '/lib/BookingEngine.php';
    $pdo->beginTransaction();
    try {
        if (!BookingEngine::isSlotAvailable($appt['provider_id'], $appt['service_id'], $newDatetime)) {
            $pdo->rollBack();
            json_out(['ok'=>false,'error'=>'That slot is no longer available. Please choose another time.'], 409);
        }
        $pdo->prepare(
            'UPDATE bk_appointments
             SET start_datetime=?, end_datetime=?, status="pending",
                 reminder_24h_sent=0, reminder_1h_sent=0
             WHERE id=?'
        )->execute([$newDatetime, $newEndDatetime, $apptId]);
        $pdo->commit();
    } catch (\Throwable $e) {
        $pdo->rollBack();
        throw $e;
    }

    // Send reschedule confirmation email
    $fullRow = $pdo->prepare('
        SELECT a.ref, a.start_datetime,
               c.name as customer_name, c.email as customer_email,
               s.name as service_name,
               p.name as provider_name
        FROM bk_appointments a
        JOIN bk_customers c ON c.id = a.customer_id
        JOIN bk_services s  ON s.id = a.service_id
        JOIN bk_providers p ON p.id = a.provider_id
        WHERE a.id=?
    ');
    $fullRow->execute([$apptId]);
    $row = $fullRow->fetch();

    if ($row) {
        $fmtDate = date('D, d M Y \a\t g:ia', strtotime($row['start_datetime']));
        $html = "
            <h2>Appointment Rescheduled — {$row['service_name']}</h2>
            <p>Hi {$row['customer_name']},</p>
            <p>Your appointment has been rescheduled to:</p>
            <table>
                <tr><td><strong>Reference:</strong></td><td>{$row['ref']}</td></tr>
                <tr><td><strong>Service:</strong></td><td>{$row['service_name']}</td></tr>
                <tr><td><strong>Provider:</strong></td><td>{$row['provider_name']}</td></tr>
                <tr><td><strong>New Date &amp; Time:</strong></td><td>{$fmtDate}</td></tr>
            </table>
            <p><a href=\"" . APP_URL . "/customer/dashboard.php\">View your bookings →</a></p>";
        $text = "Rescheduled — {$row['ref']}\nService: {$row['service_name']}\nProvider: {$row['provider_name']}\nNew Date: {$fmtDate}";
        try {
            send_mail($row['customer_email'], $row['customer_name'],
                "Appointment Rescheduled — {$row['service_name']} with {$row['provider_name']}", $html, $text);
        } catch (\Throwable $e) {
            error_log('Reschedule email error: ' . $e->getMessage());
        }
    }

    json_out(['ok'=>true, 'new_datetime'=>$newDatetime, 'message'=>'Appointment rescheduled.']);
}
