<?php

declare(strict_types=1);

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\exceptions\ForgotPasswordLinkExpiredException;
use DateTimeImmutable;
use function apexl\Io\config;

/**
 * @property int $id
 * @property string $email
 * @property string $hash
 * @property DateTimeImmutable $created
 * @property bool $used
 */
class PasswordReset extends Entity
{
    use hasCasts;

    final public const string TABLE = 'password_reset';

    public function __construct($table = '', $primaryKey = 'id', $extends = null)
    {
        parent::__construct(self::TABLE, $primaryKey, $extends);
    }

    /**
     * @throws RecordNotFoundException
     * @throws ForgotPasswordLinkExpiredException
     */
    public static function fromHash(string $passwordReset, bool $allowUnusable = false): PasswordReset
    {
        $passwordReset = static::from('hash', $passwordReset);

        if (!$allowUnusable && !$passwordReset->isUsable()) {
            throw new ForgotPasswordLinkExpiredException();
        }

        return $passwordReset;
    }

    public function isUsable(): bool
    {
        return !$this->isExpired() && !$this->isUsed();
    }

    public function isExpired(): bool
    {
        return (time() - $this->created->getTimestamp()) >= config('auth.reset_password_lifetime');
    }

    public function isUsed(): bool
    {
        return $this->used;
    }

    public function casts(): array
    {
        return [
            'id' => Casts::INT,
            'created' => Casts::DATETIME_STAMP,
            'used' => Casts::BOOL,
        ];
    }

    public function markUsed(): void
    {
        $this->used = true;
        $this->store();
    }
}