<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class ApiToken extends Model
{
    protected $fillable = [
        'user_id',
        'organization_id',
        'name',
        'token_prefix',
        'token_hash',
        'last_used_at',
        'revoked_at',
    ];

    protected $hidden = [
        'token_hash',
    ];

    protected function casts(): array
    {
        return [
            'user_id' => 'integer',
            'organization_id' => 'integer',
            'last_used_at' => 'datetime',
            'revoked_at' => 'datetime',
        ];
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function organization()
    {
        return $this->belongsTo(Organization::class);
    }

    public function isRevoked(): bool
    {
        return $this->revoked_at !== null;
    }

    public function matchesSecret(string $secret): bool
    {
        return hash_equals((string) $this->token_hash, hash('sha256', $secret));
    }

    public static function issueForUser(User $user, string $name): array
    {
        $secret = Str::random(64);

        $token = self::query()->create([
            'user_id' => (int) $user->id,
            'organization_id' => (int) $user->organization_id,
            'name' => trim($name) !== '' ? trim($name) : 'Integracion',
            'token_prefix' => substr($secret, 0, 8),
            'token_hash' => hash('sha256', $secret),
        ]);

        return [$token, $token->id.'|'.$secret];
    }

    public static function findFromPlainTextToken(?string $plainTextToken): ?self
    {
        $plainTextToken = trim((string) $plainTextToken);
        if ($plainTextToken === '' || ! str_contains($plainTextToken, '|')) {
            return null;
        }

        [$tokenId, $secret] = explode('|', $plainTextToken, 2);
        $tokenId = (int) $tokenId;
        $secret = trim($secret);

        if ($tokenId <= 0 || $secret === '') {
            return null;
        }

        $token = self::query()
            ->with('user')
            ->whereKey($tokenId)
            ->whereNull('revoked_at')
            ->first();

        if (! $token || ! $token->matchesSecret($secret)) {
            return null;
        }

        return $token;
    }
}
