<?php
define('VFM_APP', true);

$baseDir = dirname(__DIR__, 2);

require_once $baseDir.'/config.php';

session_name($_CONFIG['session_name']);
session_start();

if (version_compare(PHP_VERSION, '8.1.0', '<')) {
    die('OAuth requires PHP 8.1 or higher. Current version: '.PHP_VERSION);
}

require_once $baseDir.'/class/class.setup.php';
require_once $baseDir.'/class/class.utils.php';
require_once $baseDir.'/class/class.template.php';
require_once $baseDir.'/class/class.gatekeeper.php';
require_once $baseDir.'/class/class.updater.php';
require_once $baseDir.'/class/class.resetter.php';

require_once __DIR__.'/vendor/autoload.php';

$setUp = new SetUp();
$gateKeeper = new GateKeeper();
$updater = new Updater();

$USERS_FILE = $baseDir.'/_content/users/users.php';
$scriptUrl = rtrim($setUp->getConfig('script_url'), '/').'/';
$REDIRECT_URI = $scriptUrl.'vfm-admin/assets/oauth/callback.php';

function buildProvider($providerName, $redirectUri) {
    global $setUp;

    switch ($providerName) {
        case 'google':
            if (empty($setUp->getConfig('oauth_google_client_id'))) {
                return null;
            }
            return new League\OAuth2\Client\Provider\Google([
                'clientId'     => $setUp->getConfig('oauth_google_client_id'),
                'clientSecret' => $setUp->getConfig('oauth_google_client_secret'),
                'redirectUri'  => $redirectUri,
            ]);

        case 'github':
            if (empty($setUp->getConfig('oauth_github_client_id'))) {
                return null;
            }
            return new League\OAuth2\Client\Provider\Github([
                'clientId'     => $setUp->getConfig('oauth_github_client_id'),
                'clientSecret' => $setUp->getConfig('oauth_github_client_secret'),
                'redirectUri'  => $redirectUri,
            ]);

        case 'linkedin':
            if (empty($setUp->getConfig('oauth_linkedin_client_id'))) {
                return null;
            }
            return new League\OAuth2\Client\Provider\LinkedIn([
                'clientId'     => $setUp->getConfig('oauth_linkedin_client_id'),
                'clientSecret' => $setUp->getConfig('oauth_linkedin_client_secret'),
                'redirectUri'  => $redirectUri,
            ]);

        default:
            return null;
    }
}

function getOAuthEmail($providerName, $resourceOwner) {
    if ($providerName === 'linkedin') {
        $email = $resourceOwner->getEmail();
        if (!$email) {
            $data = $resourceOwner->toArray();
            $email = $data['email'] ?? null;
        }
        return $email;
    }
    return $resourceOwner->getEmail();
}

if (!isset($_GET['code'])) {
    $providerName = $_GET['provider'] ?? 'google';
    $provider = buildProvider($providerName, $REDIRECT_URI);

    if (!$provider) {
        die('OAuth provider not available: ' . htmlspecialchars($providerName));
    }

    $_SESSION['oauth_provider'] = $providerName;

    $authUrl = $provider->getAuthorizationUrl();
    $_SESSION['oauth2state'] = $provider->getState();
    header('Location: ' . $authUrl);
    exit;
}

try {
    $providerName = $_SESSION['oauth_provider'] ?? 'google';
    $provider = buildProvider($providerName, $REDIRECT_URI);

    if (!$provider) {
        throw new Exception('OAuth provider not configured: ' . $providerName);
    }

    if (empty($_GET['state']) || ($_SESSION['oauth2state'] ?? null) !== $_GET['state']) {
        unset($_SESSION['oauth2state']);
        throw new Exception('Invalid state parameter');
    }

    $token = $provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
    ]);

    $resourceOwner = $provider->getResourceOwner($token);
    $email = strtolower(trim(getOAuthEmail($providerName, $resourceOwner)));

    if (empty($email)) {
        throw new Exception('Could not retrieve email from ' . ucfirst($providerName));
    }

    $username = $email;
    $found = $updater->findUser($email, true);

    if ($found) {
        $users = $gateKeeper->getUsers();
        if (is_array($users)) {
            foreach ($users as $user) {
                if (isset($user['email']) && strtolower($user['email']) === $email) {
                    $username = $user['name'];
                    break;
                }
            }
        }
    } else {
        $found = $updater->findUser($email);
    }

    if (!$found) {
        $randomPass = '';
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&*';
        $max = strlen($chars) - 1;
        for ($i = 0; $i < 16; $i++) {
            $randomPass .= $chars[random_int(0, $max)];
        }

        $salt = $setUp->getConfig('salt');
        $hashedPass = password_hash($salt.urlencode($randomPass), PASSWORD_BCRYPT);

        $users = $gateKeeper->getUsers();
        if (!is_array($users)) $users = array();

        $users[] = array(
            'name'  => $username,
            'pass'  => $hashedPass,
            'role'  => $setUp->getConfig('registration_role', 'user'),
            'email' => $email,
        );
        Utils::writePhpData($USERS_FILE, '$_USERS', $users);

        try {
            require_once $baseDir.'/assets/mail/vendor/autoload.php';

            $gateKeeper = new GateKeeper();
            $mail = new PHPMailer\PHPMailer\PHPMailer();
            $resetter = new Resetter();
            $resetter->sendUserReminder($mail, $email, $username, true);
        } catch (Exception $e) {
            error_log('OAuth email error: '.$e->getMessage());
            Utils::setWarning('Account created. Check email for reset link or request a new one from the login page.');
        }
    }

    $_SESSION['vfm_user_name'] = $username;
    $_SESSION['vfm_logged_in'] = 1;
    $_SESSION['vfm_user_used'] = null;
    $_SESSION['vfm_user_space'] = null;

    header('Location: ' . $scriptUrl);
    exit;

} catch (Exception $e) {
    $errorMsg = 'OAuth login failed: ' . $e->getMessage();
    error_log($errorMsg);
    die($errorMsg);
}
