<?php

namespace App\Master;

use App\Master\Models\ApiToken;
use App\Master\Models\ApiUser;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Str;

class ApiUserRepository
{
    public function update(ApiUser $user, array $input): void
    {
        $user->update([
            'name' => $input['name'] ?? '',
            'is_active' => $input['is_active'] ?? false,
            'token_type' => $input['token_type'] ?? ApiToken::TYPE_OAUTH,
            'notes' => $input['notes'] ?? null,
        ]);
        if ($input['token_type'] !== ApiToken::TYPE_OAUTH) {
            $user->update([
                'client_id' => null,
                'client_secret' => null,
            ]);
        }
        $user->tenants()->sync($input['tenants'] ?? []);
    }

    public function createAuthCredentials(ApiUser $user): void
    {
        match ($user->token_type) {
            'persistent' => $this->createStaticToken($user),
            default => $this->createOAuthCredentials($user)
        };
    }

    public function expireToken(ApiToken $token): void
    {
        $token->update([
            'expires_at' => Carbon::now(),
        ]);
    }

    public function getAccessToken(string $client_id, string $client_secret): ApiToken
    {
        $user = ApiUser::query()
            ->where('is_active', 1)
            ->where('client_id', $client_id)
            ->firstOrFail();
        if (decrypt($user->client_secret) !== $client_secret) {
            throw new ModelNotFoundException('User not found');
        }
        return $this->createOAuthToken($user);
    }

    private function createOAuthToken(ApiUser $user): ApiToken
    {
        return $user->tokens()->create([
            'token_type' => ApiToken::TYPE_OAUTH,
            'expires_at' => Carbon::now()->addSeconds(config('auth.api_users.oauth_token_expiry')),
            'token' => Str::random(42),
        ]);
    }

    private function createOAuthCredentials(ApiUser $user): void
    {
        $user->update([
            'credentials_last_updated_at' => Carbon::now(),
            'credentials_due_for_update_at' => Carbon::now()
                ->addDays(config('auth.api_users.credential_refresh_expiry')),
            'client_id' => Str::slug($user->name . Str::random(12)),
            'client_secret' => encrypt(Str::random(22)),
        ]);
    }

    private function createStaticToken(ApiUser $user): void
    {
        $user->tokens()->create([
            'token_type' => 'persistent',
            'expires_at' => Carbon::now()->addDays(config('auth.api_users.credential_refresh_expiry')),
            'token' => Str::random(42),
        ]);
    }
}
