<?php
/**
 * Password reset: user requests (logged for admin) and admin-only reset.
 */

require_once __DIR__ . '/user-defaults.php';
require_once __DIR__ . '/memorable-password.php';
require_once __DIR__ . '/audit.php';
require_once __DIR__ . '/user-roles.php';
require_once __DIR__ . '/settings.php';

function nazareth_password_reset_max_requests_per_hour(): int
{
    return 5;
}

function nazareth_password_reset_requests_last_hour(?string $ip = null): int
{
    global $pdo;

    if ($ip === null) {
        $ip = $_SERVER['REMOTE_ADDR'] ?? null;
    }
    if (!$ip || !isset($pdo)) {
        return 0;
    }

    try {
        $pdo->query('SELECT 1 FROM activity_logs LIMIT 1');
    } catch (PDOException $e) {
        return 0;
    }

    $stmt = $pdo->prepare("
        SELECT COUNT(*) AS c
        FROM activity_logs
        WHERE action IN ('password_reset_requested', 'password_reset_request_denied')
          AND ip_address = ?
          AND created_at >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
    ");
    $stmt->execute([$ip]);
    $row = $stmt->fetch();
    return $row ? (int) $row['c'] : 0;
}

function nazareth_can_request_password_reset(?string $ip = null): bool
{
    return nazareth_password_reset_requests_last_hour($ip) < nazareth_password_reset_max_requests_per_hour();
}

/** Roles that may request a reset via church sign-in. */
function nazareth_password_reset_allowed_roles(): array
{
    return array_merge(['admin'], nazarethChurchStaffRoleSlugs());
}

/**
 * Help text / contact shown on forgot-password pages.
 */
function nazareth_password_reset_help_message(): string
{
    $custom = trim((string) getSetting('password_reset_help_message', ''));
    if ($custom !== '') {
        return $custom;
    }
    $phone = trim((string) getSetting('password_reset_help_phone', ''));
    if ($phone !== '') {
        return 'Contact your church administrator' . ($phone !== '' ? ' at ' . $phone : '') . ' to complete the reset.';
    }
    return 'Contact your church administrator to complete the reset. Only an administrator can set a new password for your account.';
}

/**
 * Submit a password reset request (does not change the password).
 * Always returns ok=true to avoid revealing whether the username exists.
 *
 * @return array{ok: bool, code: string}
 */
function nazareth_request_password_reset(PDO $pdo, string $username, string $portal = 'main'): array
{
    $username = trim($username);
    $ip = $_SERVER['REMOTE_ADDR'] ?? null;

    if ($username === '') {
        return ['ok' => false, 'code' => 'empty_username'];
    }

    if (!nazareth_can_request_password_reset($ip)) {
        logActivity(
            'password_reset_request_denied',
            'Rate limit: ' . $username,
            ['username' => $username, 'portal' => $portal],
            null,
            $ip
        );
        return ['ok' => false, 'code' => 'rate_limit'];
    }

    $stmt = $pdo->prepare('SELECT id, username, role, active, full_name FROM users WHERE username = ?');
    $stmt->execute([$username]);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($user && !empty($user['active']) && in_array($user['role'] ?? '', nazareth_password_reset_allowed_roles(), true)) {
        logActivity(
            'password_reset_requested',
            'Password reset requested: ' . $user['username'] . ' (' . ($user['role'] ?? '') . ')',
            [
                'user_id' => (int) $user['id'],
                'username' => $user['username'],
                'full_name' => $user['full_name'] ?? '',
                'role' => $user['role'] ?? '',
                'portal' => $portal,
            ],
            (int) $user['id'],
            $ip
        );
    } else {
        logActivity(
            'password_reset_request_denied',
            'Reset request (no matching active account): ' . $username,
            ['username' => $username, 'portal' => $portal],
            null,
            $ip
        );
    }

    // Same response whether or not the account exists (reduces username enumeration).
    return ['ok' => true, 'code' => 'requested'];
}

/**
 * Generate a one-time temporary password (color + food, e.g. redpepper).
 */
function nazareth_generate_temp_password(): string
{
    return nazareth_generate_memorable_password();
}

/**
 * Admin-only: set a random temporary password; user must change on next login.
 *
 * @return array{ok: bool, temp_password?: string, error?: string}
 */
function nazareth_admin_reset_user_password(PDO $pdo, int $targetUserId, int $adminUserId): array
{
    $stmt = $pdo->prepare('SELECT id, username, role, active FROM users WHERE id = ?');
    $stmt->execute([$targetUserId]);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$user) {
        return ['ok' => false, 'error' => 'User not found.'];
    }
    if ($user['role'] === 'system_admin') {
        return ['ok' => false, 'error' => 'System administrator passwords can only be reset from the system console.'];
    }
    if (empty($user['active'])) {
        return ['ok' => false, 'error' => 'Cannot reset password for an inactive account.'];
    }

    $temp = nazareth_generate_temp_password();
    $hash = password_hash($temp, PASSWORD_DEFAULT);

    try {
        $pdo->prepare('UPDATE users SET password = ?, must_change_password = 1 WHERE id = ?')
            ->execute([$hash, $targetUserId]);
    } catch (PDOException $e) {
        if (strpos($e->getMessage(), 'Unknown column') !== false) {
            $pdo->prepare('UPDATE users SET password = ? WHERE id = ?')->execute([$hash, $targetUserId]);
        } else {
            throw $e;
        }
    }

    logActivity(
        'password_reset_admin',
        'Administrator reset password for: ' . $user['username'],
        ['target_user_id' => $targetUserId, 'target_username' => $user['username']],
        $adminUserId,
        $_SERVER['REMOTE_ADDR'] ?? null
    );

    return ['ok' => true, 'temp_password' => $temp, 'username' => $user['username']];
}

/**
 * @return list<array<string, mixed>>
 */
function nazareth_recent_password_reset_requests(PDO $pdo, int $limit = 20): array
{
    try {
        $pdo->query('SELECT 1 FROM activity_logs LIMIT 1');
    } catch (PDOException $e) {
        return [];
    }

    $limit = max(1, min(50, $limit));
    $stmt = $pdo->prepare("
        SELECT id, description, details, user_id, ip_address, created_at
        FROM activity_logs
        WHERE action = 'password_reset_requested'
          AND created_at >= DATE_SUB(NOW(), INTERVAL 14 DAY)
        ORDER BY created_at DESC
        LIMIT " . (int) $limit
    );
    $stmt->execute();
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach ($rows as &$row) {
        if (!empty($row['details']) && is_string($row['details'])) {
            $decoded = json_decode($row['details'], true);
            $row['details_parsed'] = is_array($decoded) ? $decoded : [];
        } else {
            $row['details_parsed'] = [];
        }
    }
    unset($row);
    return $rows;
}

/** @deprecated Self-service instant reset removed for security. */
function nazareth_reset_church_user_password(PDO $pdo, string $username): array
{
    return nazareth_request_password_reset($pdo, $username, 'main');
}

/** @deprecated Self-service instant reset removed for security. */
function nazareth_reset_data_collector_password(PDO $pdo, string $username): array
{
    return nazareth_request_password_reset($pdo, $username, 'mobile');
}
