<?php
declare(strict_types=1);
namespace PpPhp\Generated\SocialAuth;

/**
 * GitHub OAuth 2.0.
 *
 * GitHub is NOT an OpenID Connect provider: there is no id_token to verify, so
 * identity comes from calling the API with the access token. That is safe here
 * because the token was just exchanged over TLS using our client secret, and
 * `state` was already validated by SocialAuthManager.
 *
 * The primary address needs a second call — /user only returns a public email,
 * which is usually null — and /user/emails is the only place the verified flag
 * is exposed.
 */
final class GitHubProvider extends AbstractProvider
{
    public function id(): string { return 'github'; }

    public function authorizationUrl(array $t): string
    {
        return $this->query('https://github.com/login/oauth/authorize', [
            'client_id'     => $this->value('client_id', 'GITHUB_CLIENT_ID'),
            'redirect_uri'  => $this->callbackUri(),
            'scope'         => 'read:user user:email',
            'state'         => $t['state'],
            'allow_signup'  => 'true',
        ]);
    }

    public function identity(array $r, array $t): array
    {
        $this->failOnProviderError($r);
        if (empty($r['code'])) {
            throw new \RuntimeException('GitHub did not return an authorization code.');
        }
        $tokens = $this->token('https://github.com/login/oauth/access_token', [
            'client_id'     => $this->value('client_id', 'GITHUB_CLIENT_ID'),
            'client_secret' => $this->value('client_secret', 'GITHUB_CLIENT_SECRET'),
            'code'          => $r['code'],
            'redirect_uri'  => $this->callbackUri(),
        ]);
        $access = (string) ($tokens['access_token'] ?? '');
        if ($access === '') {
            throw new \RuntimeException((string) ($tokens['error_description'] ?? 'GitHub did not return an access token.'));
        }

        $headers = [
            'Authorization: Bearer ' . $access,
            'User-Agent: PPPHP-SocialAuth',
            'X-GitHub-Api-Version: 2022-11-28',
        ];
        $user = HttpClient::get('https://api.github.com/user', $headers);
        if (empty($user['id'])) {
            throw new \RuntimeException('GitHub did not return a profile.');
        }

        // Prefer the primary VERIFIED address; fall back to the public one.
        $email = (string) ($user['email'] ?? '');
        $verified = false;
        $list = HttpClient::get('https://api.github.com/user/emails', $headers);
        foreach (is_array($list) ? $list : [] as $row) {
            if (!is_array($row) || empty($row['primary'])) continue;
            $email = (string) ($row['email'] ?? $email);
            $verified = $this->verified($row['verified'] ?? false);
            break;
        }

        return [
            'provider'       => 'github',
            'subject'        => (string) $user['id'],
            'email'          => $email,
            'email_verified' => $verified,
            'name'           => (string) ($user['name'] ?? $user['login'] ?? ''),
            'picture'        => (string) ($user['avatar_url'] ?? ''),
            'raw'            => is_array($user) ? $user : [],
        ];
    }
}
