<?php

namespace WPUF\Social;

use Hybridauth\Provider\Facebook;

/**
 * Custom Facebook Provider
 *
 * This extends the original Facebook provider to handle cases where
 * the access token is null, preventing the TypeError that occurs
 * when get_kid_from_oidc_token() receives null instead of a string.
 */
class Custom_Facebook_Provider extends Facebook
{
    /**
     * Override the main getUserProfile method to add better debugging
     * and fallback handling.
     *
     * @return \Hybridauth\User\Profile|null
     */
    public function getUserProfile()
    {
        $accessToken = $this->getStoredData('access_token');

        // If no stored access token, try to get it from the full token array
        if (empty($accessToken)) {
            // Check if we're connected (this might trigger token storage)
            if ($this->isConnected()) {
                $accessToken = $this->getStoredData('access_token');
            }

            // If still no access token, we can't proceed
            if (empty($accessToken)) {
                return null;
            }
        }

        if ( ! is_string( $accessToken ) ) {
            return $this->getUserProfileFromAccessToken();
        }

        // Try OIDC first, then fallback to access token method
        try {
            $profile = $this->getUserProfileFromOIDCToken();
            if (null !== $profile) {
                return $profile;
            }
        } catch ( \Exception $e ) {
            return null;
        }

        // Fallback to access token method
        try {
            return $this->getUserProfileFromAccessToken();
        } catch ( \Exception $e ) {
            return null;
        }
    }

    /**
     * Get the user profile from OIDC token.
     *
     * Overridden to add null check for access token before calling
     * get_kid_from_oidc_token() to prevent TypeError.
     *
     * @return \Hybridauth\User\Profile|null
     */
    public function getUserProfileFromOIDCToken()
    {
        $accessToken = $this->getStoredData('access_token');

        // Check if access token is valid before proceeding
        // This prevents the TypeError when access token is null
        if (empty($accessToken) || !is_string($accessToken)) {
            return null;
        }

        $kid = $this->get_kid_from_oidc_token($accessToken);

        if (!$kid) {
            return null;
        }

        // Since we can't call parent method (it would call original get_kid_from_oidc_token),
        // we need to skip OIDC token method and return null to fallback to access token method
        return null;
    }

    /**
     * Public method to access stored data for debugging
     *
     * @param string $key
     * @return mixed
     */
    public function getStoredDataPublic($key)
    {
        return $this->getStoredData($key);
    }

    /**
     * Override parent method to handle the case where access token is null
     *
     * @param string $accessToken
     * @return string|null
     */
    private function get_kid_from_oidc_token($accessToken)
    {
        // Additional safety check
        if (!is_string($accessToken) || empty($accessToken)) {
            return null;
        }

        $segments = explode('.', $accessToken);

        if (count($segments) !== 3) {
            return null;
        }

        $payload = json_decode(base64_decode($segments[0] ?? ''));

        if (!is_object($payload) || !isset($payload->kid)) {
            return null;
        }

        return $payload->kid;
    }
}