<?php

namespace apexl\Io\modules\user\entities;

use apexl\entityCore\enums\Casts;
use apexl\entityCore\traits\hasCasts;
use apexl\Io\exceptions\RecordNotFoundException;
use apexl\Io\includes\Entity;
use apexl\Io\modules\user\entities\operators\RefreshTokenOperator;
use DateTime;
use DateTimeImmutable;
use JsonSerializable;
use function apexl\Io\config;

/**
 * @property int $user_id
 * @property string $token
 * @property DateTimeImmutable $expiry
 *
 */
class RefreshToken extends Entity implements JsonSerializable
{
    use hasCasts;

    public final const string TABLE = 'refresh_tokens';
    public final const string PRIMARY_KEY = 'user_id';

    public function __construct()
    {
        parent::__construct(self::TABLE, self::PRIMARY_KEY);
        $this->setOperator(new RefreshTokenOperator(self::TABLE, self::PRIMARY_KEY));
    }

    /**
     * @throws RecordNotFoundException
     */
    public static function fromToken(string $token): RefreshToken
    {
        return self::from('token', self::hashToken($token));
    }

    public static function hashToken(string $token): string
    {
        return hash(config('auth.refresh.algorithm'), $token . config('auth.refresh.salt'));
    }

    public static function newExpiryFrom(?int $now = null): DateTimeImmutable
    {
        $expiry = new DateTime();
        $lifetime = config('auth.refresh.lifetime');
        $expiry->setTimestamp(($now ?? time()) + $lifetime);

        return DateTimeImmutable::createFromMutable($expiry);
    }

    public function casts(): array
    {
        return [
            'user_id' => Casts::INT,
            'expiry' => Casts::DATETIME_STAMP,
        ];
    }

    public function isExpired(): bool
    {
        return $this->expiry && $this->expiry < new DateTimeImmutable();
    }

    /**
     * @throws RecordNotFoundException
     */
    public function user(): userEntity
    {
        return userEntity::fromPrimaryKey($this->user_id);
    }

    public function jsonSerialize(): string
    {
        return $this->data['token'];
    }
}
