<?php

class CfPasswordReset
{
    /**
     * @var PDO
     */
    private $dbConnection;

    public function __construct()
    {
        $this->dbConnection = CfPdo::getInstance()->getConnection();
    }

    /**
     * @param string $username
     * @param int $length
     * @param int $expireAfterHours
     * @return string|null
     *
     * Returns token if it successfully issued
     */
    public function generateToken(string $username, int $expireAfterHours, int $length = 12): ?string
    {
        $bindData = [
            ':token' => generateRandomString($length),
            ':username' => $username,
            ':expires_at' => date('Y-m-d H:i:s', strtotime("+$expireAfterHours hours"))
        ];

        $statement = $this->dbConnection->prepare(
            'INSERT INTO password_reset_tokens
                   (username, token, expires_at)
                   VALUES (:username, :token, :expires_at)'
        );

        return ($statement->execute($bindData)) ? $bindData[':token'] : null;
    }

    /**
     * @param string $token
     * @return string|null
     *
     * Returns username if the token is valid, otherwise null
     */
    public function verifyToken(string $token): ?string
    {
        $statement = $this->dbConnection->prepare(
            'SELECT username FROM password_reset_tokens WHERE token = ? AND expires_at >= now()'
        );
        $statement->execute([$token]);
        $result = $statement->fetch(PDO::FETCH_ASSOC);

        return $result['username'] ?? null;
    }

    /**
     * @param string $token
     * @return int
     *
     * Revokes provided token
     */
    public function revokeToken(string $token): int
    {
        $statement = $this->dbConnection->prepare(
            'DELETE FROM password_reset_tokens WHERE token = ?'
        );
        $statement->execute([$token]);

        return $statement->rowCount();
    }

    /**
     * @param string $token
     * @return bool
     *
     * Revokes all tokens belong to a user
     */
    public function revokeAllUserTokens(string $username): bool
    {
        $statement = $this->dbConnection->prepare(
            'DELETE FROM password_reset_tokens WHERE username = ?'
        );
        return $statement->execute([$username]);
    }
}
