<?php
/**
 * Google Authentication Controller - Complete Revamp
 * Handles all Google OAuth login and registration flows with proper database operations
 */

require_once __DIR__ . '/../config/google-oauth.php';
require_once __DIR__ . '/../models/User.php';
require_once __DIR__ . '/../middleware/auth.php';

use Google\Service\Oauth2;

class GoogleAuthController {
    private $userModel;
    private $conn;

    public function __construct($conn) {
        $this->conn = $conn;
        $this->userModel = new User($conn);
    }

    /**
     * Initiate Google OAuth login flow
     */
    public function login() {
        try {
            // Ensure session is started
            if (session_status() === PHP_SESSION_NONE) {
                session_start();
            }

            // Get Google Client with state generation
            $client = getGoogleClient(true);
            
            // Generate authorization URL
            $authUrl = $client->createAuthUrl();
            
            // Redirect to Google
            header('Location: ' . $authUrl);
            exit;
            
        } catch (Exception $e) {
            error_log('Google OAuth Login Initiation Error: ' . $e->getMessage());
            error_log('Stack trace: ' . $e->getTraceAsString());
            
            if (session_status() === PHP_SESSION_NONE) {
                session_start();
            }
            
            $_SESSION['errors'] = ['Failed to initiate Google login. Please try again.'];
            header('Location: /mfanyakazi/public/auth/login');
            exit;
        }
    }

    /**
     * Handle Google OAuth callback
     * Processes the authorization code and logs in/registers the user
     */
    public function callback() {
        try {
            // Ensure session is started
            if (session_status() === PHP_SESSION_NONE) {
                session_start();
            }

            // Check for Google errors
            if (isset($_GET['error'])) {
                $errorMsg = $_GET['error'];
                $errorDescription = $_GET['error_description'] ?? '';
                error_log('Google OAuth Error: ' . $errorMsg . ' - ' . $errorDescription);
                throw new Exception('Google authentication was cancelled or failed: ' . $errorMsg);
            }

            // Check if authorization code is present
            if (!isset($_GET['code'])) {
                throw new Exception('Authorization code not received from Google');
            }

            // Validate state parameter for CSRF protection
            if (isset($_GET['state'])) {
                if (!validateOAuthState($_GET['state'])) {
                    error_log('OAuth state validation failed. Expected: ' . ($_SESSION['oauth_state'] ?? 'NOT SET') . ', Got: ' . $_GET['state']);
                    throw new Exception('Security validation failed: Invalid OAuth state');
                }
                clearOAuthState();
            } else {
                error_log('Warning: OAuth state parameter missing from callback');
            }

            // Get Google Client (without generating new state)
            $client = getGoogleClient(false);

            // Exchange authorization code for access token
            try {
                $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
            } catch (Exception $tokenError) {
                error_log('Token fetch exception: ' . $tokenError->getMessage());
                error_log('Token fetch exception type: ' . get_class($tokenError));
                throw new Exception('Failed to exchange authorization code: ' . $tokenError->getMessage());
            }

            // Check for token errors
            if (isset($token['error'])) {
                $errorMsg = $token['error'];
                if (isset($token['error_description'])) {
                    $errorMsg .= ': ' . $token['error_description'];
                }
                error_log('Token exchange error: ' . $errorMsg);
                throw new Exception('Failed to get access token: ' . $errorMsg);
            }

            // Set access token
            $client->setAccessToken($token);

            // Get user info from Google
            $oauth2 = new Oauth2($client);
            $googleUser = $oauth2->userinfo->get();

            // Validate we got complete user data
            if (empty($googleUser->id)) {
                throw new Exception('Incomplete user data: Missing Google ID');
            }

            if (empty($googleUser->email)) {
                throw new Exception('Incomplete user data: Missing email address');
            }

            // Process the Google user data
            $this->processGoogleUser($googleUser, $token);

        } catch (Exception $e) {
            // Log the error for debugging
            error_log('Google OAuth Callback Error: ' . $e->getMessage());
            error_log('Stack trace: ' . $e->getTraceAsString());
            error_log('GET params: ' . print_r($_GET, true));

            if (session_status() === PHP_SESSION_NONE) {
                session_start();
            }

            $_SESSION['errors'] = ['Google authentication failed. Please try again.'];
            header('Location: /mfanyakazi/public/auth/login');
            exit;
        }
    }

    /**
     * Process Google user data and determine login/registration flow
     */
    private function processGoogleUser($googleUser, $token) {
        try {
            $googleId = $googleUser->id;
            $email = $googleUser->email;
            $name = $googleUser->name ?? explode('@', $email)[0];
            $picture = $googleUser->picture ?? null;

            error_log('Processing Google user: ' . $email . ' (ID: ' . $googleId . ')');

            // Check if user already exists with this Google ID
            $existingUser = $this->findUserByGoogleId($googleId);

            if ($existingUser) {
                // User exists with Google ID - log them in
                error_log('User found with Google ID, logging in...');
                $this->loginExistingUser($existingUser, $token, $picture);
                return;
            }

            // Check if user exists with same email (but different Google ID)
            $existingUserByEmail = $this->findUserByEmail($email);

            if ($existingUserByEmail) {
                // Link Google account to existing user
                error_log('User found with email, linking Google account...');
                $this->linkGoogleAccount($existingUserByEmail, $googleId, $token, $picture);
                return;
            }

            // New user - redirect to role selection
            error_log('New user, redirecting to role selection...');
            $this->redirectToRoleSelection($googleUser, $token);

        } catch (Exception $e) {
            error_log('Error processing Google user: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Find user by Google ID
     */
    private function findUserByGoogleId($googleId) {
        try {
            $stmt = $this->conn->prepare("SELECT * FROM users WHERE google_id = ? LIMIT 1");
            if (!$stmt) {
                error_log('Error preparing findUserByGoogleId query: ' . $this->conn->error);
                return false;
            }

            $stmt->bind_param("s", $googleId);
            $stmt->execute();
            $result = $stmt->get_result();

            return $result->fetch_assoc();
        } catch (Exception $e) {
            error_log('Error in findUserByGoogleId: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Find user by email
     */
    private function findUserByEmail($email) {
        try {
            $stmt = $this->conn->prepare("SELECT * FROM users WHERE email = ? LIMIT 1");
            if (!$stmt) {
                error_log('Error preparing findUserByEmail query: ' . $this->conn->error);
                return false;
            }

            $stmt->bind_param("s", $email);
            $stmt->execute();
            $result = $stmt->get_result();

            return $result->fetch_assoc();
        } catch (Exception $e) {
            error_log('Error in findUserByEmail: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Login existing user
     */
    private function loginExistingUser($user, $token, $picture = null) {
        try {
            // Update profile picture if provided and different
            if ($picture && (!isset($user['profile_picture']) || $user['profile_picture'] !== $picture)) {
                $this->updateProfilePicture($user['uuid'], $picture);
            }

            // Store access token in session
            $_SESSION['google_oauth_access_token'] = $token;

            // Set user session
            setUserSession($user);

            // Redirect based on role
            $this->redirectBasedOnRole($user['role']);

        } catch (Exception $e) {
            error_log('Error in loginExistingUser: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Link Google account to existing user
     */
    private function linkGoogleAccount($existingUser, $googleId, $token, $picture = null) {
        try {
            $this->conn->begin_transaction();

            // Update user with Google ID
            $stmt = $this->conn->prepare("UPDATE users SET google_id = ?, updated_at = NOW() WHERE uuid = ?");
            if (!$stmt) {
                throw new Exception('Failed to prepare statement: ' . $this->conn->error);
            }

            $stmt->bind_param("ss", $googleId, $existingUser['uuid']);

            if (!$stmt->execute()) {
                throw new Exception('Failed to link Google account: ' . $stmt->error);
            }

            // Update profile picture if provided
            if ($picture) {
                $this->updateProfilePicture($existingUser['uuid'], $picture);
            }

            $this->conn->commit();

            // Update user array with Google ID
            $existingUser['google_id'] = $googleId;

            // Store access token in session
            $_SESSION['google_oauth_access_token'] = $token;

            // Set user session
            setUserSession($existingUser);

            // Redirect based on role
            $this->redirectBasedOnRole($existingUser['role']);

        } catch (Exception $e) {
            $this->conn->rollback();
            error_log('Error linking Google account: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Redirect to role selection page for new users
     */
    private function redirectToRoleSelection($googleUser, $token) {
        try {
            if (session_status() === PHP_SESSION_NONE) {
                session_start();
            }

            // Store Google user data in session for role selection
            $_SESSION['google_user_data'] = [
                'id' => $googleUser->id,
                'email' => $googleUser->email,
                'name' => $googleUser->name ?? explode('@', $googleUser->email)[0],
                'picture' => $googleUser->picture ?? null,
                'token' => $token
            ];

            header('Location: /mfanyakazi/public/auth/select-role');
            exit;

        } catch (Exception $e) {
            error_log('Error redirecting to role selection: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Update user profile picture
     */
    private function updateProfilePicture($userUuid, $pictureUrl) {
        try {
            $stmt = $this->conn->prepare("UPDATE users SET profile_picture = ?, updated_at = NOW() WHERE uuid = ?");
            if ($stmt) {
                $stmt->bind_param("ss", $pictureUrl, $userUuid);
                $stmt->execute();
            }
        } catch (Exception $e) {
            // Don't throw - profile picture update is not critical
            error_log('Error updating profile picture: ' . $e->getMessage());
        }
    }

    /**
     * Redirect user based on their role
     */
    private function redirectBasedOnRole($role) {
        $redirectUrl = '/mfanyakazi/public/jobs';

        switch ($role) {
            case 'admin':
                $redirectUrl = '/mfanyakazi/public/dashboard/admin-dashboard';
                break;
            case 'employer':
                $redirectUrl = '/mfanyakazi/public/dashboard/employer-dashboard';
                break;
            case 'jobseeker':
                $redirectUrl = '/mfanyakazi/public/jobs';
                break;
        }

        header('Location: ' . $redirectUrl);
        exit;
    }
}
?>