<?php
namespace oauth;

use app\openapi\model\OAuthAccessTokenModel;
use app\openapi\model\OAuthAuthCodeModel;
use app\openapi\model\OAuthClientModel;
use app\openapi\model\OAuthRefreshTokenModel;
use OAuth2\IOAuth2GrantClient;
use OAuth2\IOAuth2GrantCode;
use OAuth2\IOAuth2RefreshTokens;
use OAuth2\Model\IOAuth2AccessToken;
use OAuth2\Model\IOAuth2AuthCode;
use OAuth2\Model\IOAuth2Client;
use OAuth2\Model\IOAuth2Token;
use OAuth2\Model\OAuth2AccessToken;
use OAuth2\Model\OAuth2AuthCode;
use OAuth2\Model\OAuth2Client;
use OAuth2\Model\OAuth2Token;

/**
 * OAuth2存储实现
 */
class OAuthStorage implements IOAuth2GrantCode, IOAuth2RefreshTokens, IOAuth2GrantClient
{
    private $salt = '';

    public function __construct($salt = null)
    {
        if (!is_null($salt)) {
            $this->salt = $salt;
        }
    }

    public function addClient($client_id, $client_secret, $redirect_uri)
    {
        // 实现添加客户端的逻辑
        $client = OAuthClientModel::create([
            'client_id'     => $client_id,
            'client_secret' => hash('sha1', $client_id . $client_secret . $this->salt),
            'redirect_uri'  => $redirect_uri,
        ]);

        return !$client->isEmpty();
    }
    
    public function getAuthCode($code): IOAuth2AuthCode
    {
        // 实现获取授权码的逻辑
        $ret = OAuthAuthCodeModel::code($code)->find();
        if (is_null($ret)) {
            throw new \Exception('授权码不存在');
        }

        return new OAuth2AuthCode($ret->client_id, '', $ret->expires, $ret->scope, null, $ret->redirect_uri);
    }

    public function createAuthCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null)
    {
        // 实现创建授权码的逻辑
        $auth = OAuthAuthCodeModel::create([
            'code'         => $code,
            'client_id'    => $client_id,
            'user_id'      => $user_id,
            'redirect_uri' => $redirect_uri,
            'expires'      => $expires,
            'scope'        => $scope,
        ]);

        return !$auth->isEmpty();
    }

    public function markAuthCodeAsUsed($code)
    {
        // 实现标记授权码为已使用的逻辑
        OAuthAuthCodeModel::code($code)->delete();
    }

    public function getClient($client_id): IOAuth2Client
    {
        // 实现获取客户端的逻辑
        $client = OAuthClientModel::clientId($client_id)->find();
        if (is_null($client)) {
            throw new \Exception('客户端不存在');
        }
        if ($client->enabled != 1) {
            throw new \Exception('客户端已禁用');
        }
        if (strtotime($client->expired_at) < time()) {
            throw new \Exception('client_id 授权已过期');
        }

        return new OAuth2Client($client->client_id, $client->client_secret, [$client->redirect_uri]);
    }

    public function checkClientCredentials(IOAuth2Client $client, $client_secret = null): bool
    {
        // 实现检查客户端凭证的逻辑
        $client = OAuthClientModel::clientId($client->getPublicId())->find();
        if (is_null($client)) {
            return false;
        }
        if (strtotime($client->expired_at) < time()) {
            throw new \Exception('client_id 授权已过期');
        }

        return $client->client_secret == hash('sha1', $client->client_id . $client_secret . $this->salt);
    }

    public function getAccessToken($access_token): IOAuth2AccessToken
    {
        // 实现获取访问令牌的逻辑
        $ret = OAuthAccessTokenModel::accessToken($access_token)->find();
        if (is_null($ret)) {
            throw new \Exception('访问令牌不存在');
        }

        return new OAuth2AccessToken($ret->client_id, $ret->access_token, $ret->expires, $ret->scope, null);
    }

    public function createAccessToken($access_token, IOAuth2Client $client, $user_id, $expires, $scope = null)
    {
        // 实现创建访问令牌的逻辑
        OAuthAccessTokenModel::create([
            'access_token' => $access_token,
            'client_id'    => $client->getPublicId(),
            'user_id'      => $user_id,
            'expires'      => $expires,
            'scope'        => $scope,
        ]);
    }

    public function checkClientCredentialsGrant(IOAuth2Client $client, $client_secret): array
    {
        // 实现检查受限授权类型的逻辑
        return ['issue_refresh_token' => true];
    }

    public function checkRestrictedGrantType(IOAuth2Client $client, $grant_type): bool
    {
        // 实现检查受限授权类型的逻辑
        return $grant_type == 'client_credentials' || $grant_type == 'refresh_token';
    }

    // IOAuth2RefreshTokens 接口方法实现
    public function getRefreshToken($refresh_token): IOAuth2Token
    {
        // 实现获取刷新令牌的逻辑
        $ret = OAuthRefreshTokenModel::refreshToken($refresh_token)->find();
        if (is_null($ret)) {
            throw new \Exception('刷新令牌不存在');
        }

        return new OAuth2Token($ret->client_id, $ret->refresh_token, $ret->expires, $ret->scope, null);
    }

    public function createRefreshToken($refresh_token, IOAuth2Client $client, $user_id, $expires, $scope = null)
    {
        // 实现创建刷新令牌的逻辑
        OAuthRefreshTokenModel::create([
            'refresh_token' => $refresh_token,
            'client_id'     => $client->getPublicId(),
            'user_id'       => $user_id,
            'expires'       => $expires,
            'scope'         => $scope,
        ]);
    }

    public function unsetRefreshToken($refresh_token)
    {
        // 实现注销刷新令牌的逻辑
        OAuthRefreshTokenModel::refreshToken($refresh_token)->delete();
    }
}
