<?php
declare(strict_types=1);

require_once __DIR__ . '/db.php';
require_once __DIR__ . '/users.php';
require_once __DIR__ . '/mailer.php';
require_once __DIR__ . '/tenant.php';

function client_session_boot(): void
{
    if (session_status() !== PHP_SESSION_ACTIVE) {
        session_start();
    }
}

function client_policy(int $tenantId): array
{
    $stmt = db()->prepare('SELECT * FROM client_policy WHERE tenant_id = ?');
    $stmt->execute([$tenantId]);
    $row = $stmt->fetch();
    if ($row) {
        return $row;
    }
    db()->prepare(
        'INSERT INTO client_policy (tenant_id, notice_hours, cancel_fee, allow_reschedule, allow_cancel)
         VALUES (?, 24, 25.00, 1, 1)'
    )->execute([$tenantId]);
    $stmt->execute([$tenantId]);
    return $stmt->fetch() ?: [
        'tenant_id' => $tenantId,
        'notice_hours' => 24,
        'cancel_fee' => 25.00,
        'allow_reschedule' => 1,
        'allow_cancel' => 1,
        'fee_note' => 'A cancellation fee may apply inside the notice window.',
    ];
}

function client_current_user(): ?array
{
    client_session_boot();
    $id = (int) ($_SESSION['client_user_id'] ?? 0);
    $tenantId = (int) ($_SESSION['client_tenant_id'] ?? 0);
    if ($id < 1 || $tenantId < 1) {
        return null;
    }
    $stmt = db()->prepare('SELECT * FROM users WHERE id = ? AND tenant_id = ?');
    $stmt->execute([$id, $tenantId]);
    $row = $stmt->fetch();
    return $row ?: null;
}

function client_require_login(string $tenantParam = ''): array
{
    $user = client_current_user();
    if ($user) {
        return $user;
    }
    header('Location: ' . APP_BASE . '/client/login.php?tenant=' . urlencode($tenantParam));
    exit;
}

function client_login_user(array $user): void
{
    client_session_boot();
    $_SESSION['client_user_id'] = (int) $user['id'];
    $_SESSION['client_tenant_id'] = (int) $user['tenant_id'];
}

function client_logout(): void
{
    client_session_boot();
    unset($_SESSION['client_user_id'], $_SESSION['client_tenant_id']);
}

function client_find_by_email(int $tenantId, string $email): ?array
{
    $email = user_normalize_email($email);
    if (!$email) {
        return null;
    }
    $stmt = db()->prepare('SELECT * FROM users WHERE tenant_id = ? AND email = ? LIMIT 1');
    $stmt->execute([$tenantId, $email]);
    $row = $stmt->fetch();
    return $row ?: null;
}

function client_set_password(int $userId, int $tenantId, string $password): void
{
    if (strlen($password) < 6) {
        throw new InvalidArgumentException('Password must be at least 6 characters.');
    }
    $hash = password_hash($password, PASSWORD_DEFAULT);
    db()->prepare('UPDATE users SET password_hash = ?, login_token = NULL, login_token_expires = NULL WHERE id = ? AND tenant_id = ?')
        ->execute([$hash, $userId, $tenantId]);
}

/**
 * Create a customer account, or attach a password to a guest created by a prior booking.
 *
 * @return array user row
 */
function client_register_account(
    int $tenantId,
    string $name,
    string $email,
    string $password,
    ?string $phone = null
): array {
    if (strlen($password) < 6) {
        throw new InvalidArgumentException('Password must be at least 6 characters.');
    }
    $emailNorm = user_normalize_email($email);
    if (!$emailNorm) {
        throw new InvalidArgumentException('Enter a valid email.');
    }
    $name = trim($name);
    if ($name === '') {
        throw new InvalidArgumentException('Name is required.');
    }
    $phoneNorm = user_normalize_phone($phone);

    $existing = client_find_by_email($tenantId, $emailNorm);
    if ($existing) {
        if (user_is_owner($existing)) {
            throw new RuntimeException('Owner accounts use the shop admin website, not the customer app.');
        }
        $hash = (string) ($existing['password_hash'] ?? '');
        if ($hash !== '') {
            throw new RuntimeException('An account already exists for that email. Sign in instead.');
        }
        db()->prepare(
            'UPDATE users SET name = ?, phone = COALESCE(?, phone), password_hash = ?, login_token = NULL, login_token_expires = NULL
             WHERE id = ? AND tenant_id = ?'
        )->execute([
            $name,
            $phoneNorm,
            password_hash($password, PASSWORD_DEFAULT),
            (int) $existing['id'],
            $tenantId,
        ]);
        $user = client_find_by_email($tenantId, $emailNorm);
        if (!$user) {
            throw new RuntimeException('Could not update that account.');
        }
        return $user;
    }

    db()->prepare(
        'INSERT INTO users (tenant_id, name, phone, email, password_hash, role) VALUES (?,?,?,?,?,?)'
    )->execute([
        $tenantId,
        $name,
        $phoneNorm,
        $emailNorm,
        password_hash($password, PASSWORD_DEFAULT),
        'customer',
    ]);
    $user = client_find_by_email($tenantId, $emailNorm);
    if (!$user) {
        throw new RuntimeException('Could not create account.');
    }
    return $user;
}

function client_verify_password(array $user, string $password): bool
{
    $hash = (string) ($user['password_hash'] ?? '');
    if ($hash === '') {
        return false;
    }
    return password_verify($password, $hash);
}

/**
 * Create a magic login link token and email it (or log via mailer).
 */
function client_send_magic_link(array $user, string $tenantParam = ''): string
{
    $token = bin2hex(random_bytes(16));
    $expires = (new DateTime('+30 minutes'))->format('Y-m-d H:i:s');
    db()->prepare('UPDATE users SET login_token = ?, login_token_expires = ? WHERE id = ?')
        ->execute([$token, $expires, (int) $user['id']]);

    $email = user_normalize_email($user['email'] ?? null);
    if (!$email) {
        throw new RuntimeException('This account has no email on file.');
    }

    $url = (isset($_SERVER['HTTP_HOST'])
        ? ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']
        : 'http://localhost')
        . APP_BASE . '/client/magic.php?tenant=' . urlencode($tenantParam)
        . '&token=' . urlencode($token);

    $tenant = get_tenant((int) $user['tenant_id']);
    $shop = (string) ($tenant['name'] ?? 'BarberShop');
    $body = "Hi {$user['name']},\n\nUse this link to sign in to your {$shop} account (expires in 30 minutes):\n\n{$url}\n\nIf you did not request this, ignore this email.";
    mail_send($email, "Sign in to {$shop}", $body, null, $shop);
    return $url;
}

function client_consume_magic_token(string $token): ?array
{
    $token = trim($token);
    if ($token === '') {
        return null;
    }
    $stmt = db()->prepare(
        'SELECT * FROM users WHERE login_token = ? AND login_token_expires IS NOT NULL AND login_token_expires > NOW() LIMIT 1'
    );
    $stmt->execute([$token]);
    $user = $stmt->fetch();
    if (!$user) {
        return null;
    }
    db()->prepare('UPDATE users SET login_token = NULL, login_token_expires = NULL WHERE id = ?')
        ->execute([(int) $user['id']]);
    return $user;
}

/**
 * @return array{allowed:bool,fee_applies:bool,hours_left:float,notice_hours:int,cancel_fee:float,message:string}
 */
function client_policy_check(int $tenantId, string $startsAt): array
{
    $policy = client_policy($tenantId);
    $notice = max(0, (int) $policy['notice_hours']);
    $fee = (float) $policy['cancel_fee'];
    $starts = new DateTime($startsAt);
    $now = new DateTime('now');
    $hoursLeft = ($starts->getTimestamp() - $now->getTimestamp()) / 3600;

    if ($starts <= $now) {
        return [
            'allowed' => false,
            'fee_applies' => false,
            'hours_left' => $hoursLeft,
            'notice_hours' => $notice,
            'cancel_fee' => $fee,
            'message' => 'This appointment is in the past and cannot be changed online.',
        ];
    }

    $feeApplies = $hoursLeft < $notice;
    if ($feeApplies) {
        return [
            'allowed' => true,
            'fee_applies' => true,
            'hours_left' => $hoursLeft,
            'notice_hours' => $notice,
            'cancel_fee' => $fee,
            'message' => sprintf(
                'Inside the %d-hour notice window. A $%s fee may apply (pay at the shop until online payments are enabled).',
                $notice,
                number_format($fee, 2)
            ),
        ];
    }

    return [
        'allowed' => true,
        'fee_applies' => false,
        'hours_left' => $hoursLeft,
        'notice_hours' => $notice,
        'cancel_fee' => $fee,
        'message' => sprintf('Outside the %d-hour window — free to cancel or reschedule.', $notice),
    ];
}

function client_layout_header(string $title, array $tenant, string $tenantParam, ?array $user = null): void
{
    $fonts = font_pairing_css((string) $tenant['font_pairing']);
    $company = shop_company_name(null, $tenant);
    ?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title><?= htmlspecialchars($title) ?></title>
  <link href="<?= htmlspecialchars($fonts['import']) ?>" rel="stylesheet">
  <link rel="stylesheet" href="<?= APP_BASE ?>/assets/public.css">
  <link rel="stylesheet" href="<?= APP_BASE ?>/assets/shop.css">
  <link rel="stylesheet" href="<?= APP_BASE ?>/assets/client.css">
  <style>
    :root {
      --primary: <?= htmlspecialchars((string) $tenant['primary_color']) ?>;
      --secondary: <?= htmlspecialchars((string) $tenant['secondary_color']) ?>;
      --font-heading: <?= $fonts['heading'] ?>;
      --font-body: <?= $fonts['body'] ?>;
    }
  </style>
</head>
<body>
<header class="site-header">
  <a class="logo" href="<?= APP_BASE ?>/?tenant=<?= urlencode($tenantParam) ?>"><?= htmlspecialchars($company) ?></a>
  <nav>
    <a href="<?= APP_BASE ?>/?tenant=<?= urlencode($tenantParam) ?>#book">Book</a>
    <a href="<?= APP_BASE ?>/shop.php?tenant=<?= urlencode($tenantParam) ?>">Shop</a>
    <?php if ($user): ?>
      <a href="<?= APP_BASE ?>/client/dashboard.php?tenant=<?= urlencode($tenantParam) ?>">My appointments</a>
      <a href="<?= APP_BASE ?>/client/logout.php?tenant=<?= urlencode($tenantParam) ?>" class="nav-cta">Log out</a>
    <?php else: ?>
      <a href="<?= APP_BASE ?>/client/login.php?tenant=<?= urlencode($tenantParam) ?>" class="nav-cta">Client login</a>
    <?php endif; ?>
  </nav>
</header>
<?php
}

function client_layout_footer(): void
{
    require_once __DIR__ . '/sn_credit.php';
    echo '<footer class="site-footer sn-footer-only">';
    sn_credit_render();
    echo '</footer></body></html>';
}
