<?php

namespace App\Http\Controllers;

use App\Http\Traits\ResponseTrait;
use App\Models\OAuthProvider;
use App\Models\User;
use App\Repositories\Contracts\UserRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;

class OAuthController extends Controller
{
    use ResponseTrait;

    private $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    /**
     * Redirect to OAuth provider
     * 
     * @param string $provider
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function redirect($provider, Request $request)
    {
        $request->validate([
            'action' => 'required|in:login,signup,link',
            'redirect_uri' => 'required|url',
        ]);

        // Validate provider
        if (!in_array($provider, ['google', 'linkedin'])) {
            return $this->errorResponse('Invalid OAuth provider');
        }

        // Generate state for CSRF protection
        $state = Str::random(40);
        
        // Store state, action, and redirect_uri in session
        session([
            'oauth_state' => $state,
            'oauth_action' => $request->action,
            'oauth_redirect_uri' => $request->redirect_uri,
            'oauth_provider' => $provider,
        ]);

        try {
            // Redirect to OAuth provider
            return Socialite::driver($provider)
                ->with(['state' => $state])
                ->redirect();
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to initiate OAuth flow: ' . $e->getMessage());
        }
    }

    /**
     * Handle OAuth callback
     * 
     * @param string $provider
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function callback($provider, Request $request)
    {
        $request->validate([
            'code' => 'required|string',
            'state' => 'required|string',
            'action' => 'required|in:login,signup,link',
            'role' => 'nullable|string|in:student,learner,researcher,recruiter',
            'redirect_uri' => 'required|url',
        ]);

        // Verify state parameter
        if ($request->state !== session('oauth_state')) {
            return $this->errorResponse('Invalid state parameter');
        }

        // Validate provider
        if (!in_array($provider, ['google', 'linkedin'])) {
            return $this->errorResponse('Invalid OAuth provider');
        }

        try {
            // Exchange authorization code for access token
            $socialUser = Socialite::driver($provider)->user();

            $action = session('oauth_action', $request->action);
            $user = null;
            $requiresProfileCompletion = false;

            if ($action === 'link') {
                // Link OAuth account to existing user
                $user = $request->user();
                if (!$user) {
                    return response()->json([
                        'code' => 401,
                        'error' => true,
                        'status' => 'error',
                        'message' => 'Authentication required to link OAuth account'
                    ], 401);
                }
            } else {
                // Find or create user
                $oauthProvider = OAuthProvider::where('provider', $provider)
                    ->where('provider_id', $socialUser->getId())
                    ->first();

                if ($oauthProvider) {
                    // Existing OAuth connection - login
                    $user = $oauthProvider->user;
                } else {
                    // Check if user exists by email
                    $user = User::where('email', $socialUser->getEmail())->first();

                    if (!$user && $action === 'signup') {
                        // Create new user
                        $user = $this->userRepository->create([
                            'name' => $socialUser->getName(),
                            'email' => $socialUser->getEmail(),
                            'password' => Hash::make(Str::random(32)), // Random password since OAuth
                            'is_verified' => true,
                            'profile_photo' => $socialUser->getAvatar(),
                        ]);

                        // Assign role if provided
                        if ($request->role) {
                            $user->assignRole($request->role);
                        }

                        $requiresProfileCompletion = true;
                    } elseif (!$user) {
                        return response()->json([
                            'code' => 404,
                            'error' => true,
                            'status' => 'error',
                            'message' => 'User not found. Please sign up first.'
                        ], 404);
                    }
                }
            }

            // Create or update OAuth provider connection
            OAuthProvider::updateOrCreate(
                [
                    'user_id' => $user->id,
                    'provider' => $provider,
                ],
                [
                    'provider_id' => $socialUser->getId(),
                    'email' => $socialUser->getEmail(),
                    'name' => $socialUser->getName(),
                    'avatar_url' => $socialUser->getAvatar(),
                    'access_token' => $socialUser->token,
                    'refresh_token' => $socialUser->refreshToken,
                    'expires_at' => now()->addSeconds($socialUser->expiresIn ?? 3600),
                ]
            );

            // Generate Sanctum token
            $token = $user->createToken('oauth-token')->plainTextToken;

            // Clear session
            session()->forget(['oauth_state', 'oauth_action', 'oauth_redirect_uri', 'oauth_provider']);

            // Check if profile is complete
            $profileComplete = !empty($user->bio) && 
                              ($user->researcherProfile || $user->learnerProfile || $user->studentProfile || $user->recruiterProfile);

            return $this->successResponse([
                'token' => $token,
                'user' => [
                    'id' => $user->id,
                    'name' => $user->name,
                    'email' => $user->email,
                    'role' => $user->getRoleNames()->first(),
                    'profile_complete' => $profileComplete,
                ],
                'requires_profile_completion' => $requiresProfileCompletion,
            ], 'OAuth authentication successful');

        } catch (\Exception $e) {
            return $this->errorResponse('OAuth authentication failed: ' . $e->getMessage());
        }
    }

    /**
     * Unlink OAuth account from user profile
     * 
     * @param string $provider
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function unlink($provider, Request $request)
    {
        // Validate provider
        if (!in_array($provider, ['google', 'linkedin'])) {
            return $this->errorResponse('Invalid OAuth provider');
        }

        $user = $request->user();
        if (!$user) {
            return response()->json([
                'code' => 401,
                'error' => true,
                'status' => 'error',
                'message' => 'Authentication required'
            ], 401);
        }

        // Find OAuth provider connection
        $oauthProvider = OAuthProvider::where('user_id', $user->id)
            ->where('provider', $provider)
            ->first();

        if (!$oauthProvider) {
            return $this->errorResponse('OAuth account not linked');
        }

        // Check if user has at least one login method remaining
        $hasPassword = !empty($user->password);
        $otherOAuthProviders = OAuthProvider::where('user_id', $user->id)
            ->where('provider', '!=', $provider)
            ->count();

        if (!$hasPassword && $otherOAuthProviders === 0) {
            return response()->json([
                'code' => 422,
                'error' => true,
                'status' => 'error',
                'message' => 'Cannot unlink OAuth account. You must have at least one login method remaining.'
            ], 422);
        }

        // Delete OAuth provider connection
        $oauthProvider->delete();

        return response()->json([
            'code' => 200,
            'error' => false,
            'status' => 'success',
            'message' => 'OAuth account unlinked successfully'
        ], 200);
    }
}
