<?php

namespace App\Http\Controllers;

use App\Models\GoogleMeetConfiguration;
use App\Models\MeetingLog;
use App\Services\GoogleMeetConfigurationService as ConfigurationService;
use App\Services\OAuth2Service;
use App\Services\MeetProvider;
use App\Services\MeetService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;

/**
 * GoogleMeetController
 * 
 * Handles all Google Meet configuration management operations.
 * Access is restricted to Super Manager role only.
 * 
 * @see design.md for full specification
 * @see requirements.md for functionality requirements
 */
class GoogleMeetController extends Controller
{
    /**
     * Configuration service instance.
     *
     * @var ConfigurationService
     */
    protected ConfigurationService $configService;

    /**
     * OAuth2 service instance.
     *
     * @var OAuth2Service
     */
    protected OAuth2Service $oauthService;

    /**
     * Meet provider instance.
     *
     * @var MeetProvider
     */
    protected MeetProvider $meetProvider;

    /**
     * Meet service instance.
     *
     * @var MeetService
     */
    protected MeetService $meetService;

    /**
     * Create a new controller instance.
     *
     * @param ConfigurationService $configService
     * @param OAuth2Service $oauthService
     * @param MeetProvider $meetProvider
     * @param MeetService $meetService
     */
    public function __construct(
        ConfigurationService $configService,
        OAuth2Service $oauthService,
        MeetProvider $meetProvider,
        MeetService $meetService
    ) {
        $this->configService = $configService;
        $this->oauthService = $oauthService;
        $this->meetProvider = $meetProvider;
        $this->meetService = $meetService;
    }

    /**
     * Display the Google Meet configuration dashboard.
     *
     * @return \Illuminate\View\View
     */
    public function index()
    {
        // Permission check: Only Super Manager can access
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can access Google Meet configuration.'
        );

        // Get configuration status
        $config = $this->configService->getConfiguration();
        $status = $this->configService->getStatusSummary();

        // Get recent logs (last 10)
        $recentLogs = MeetingLog::latest()
            ->take(10)
            ->get();

        // Get statistics
        $stats = [
            'total_meetings' => MeetingLog::meetings()->count(),
            'successful_meetings' => MeetingLog::meetings()->successful()->count(),
            'failed_meetings' => MeetingLog::meetings()->failed()->count(),
            'total_tests' => MeetingLog::tests()->count(),
            'successful_tests' => MeetingLog::tests()->successful()->count(),
            'token_refreshes' => MeetingLog::tokenRefreshes()->count(),
            'last_meeting' => MeetingLog::meetings()->successful()->latest()->first(),
        ];

        return view('config.google-meet.index', compact(
            'config',
            'status',
            'recentLogs',
            'stats'
        ));
    }

    /**
     * Show the form for creating a new configuration.
     *
     * @return \Illuminate\View\View
     */
    public function create()
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can create Google Meet configuration.'
        );

        // Check if configuration already exists
        if ($this->configService->isConfigured()) {
            return redirect()
                ->route('config.google-meet.edit')
                ->with('info', 'Configuration already exists. You can edit it here.');
        }

        return view('config.google-meet.form', [
            'config' => null,
            'isEdit' => false,
        ]);
    }

    /**
     * Store a newly created configuration.
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(Request $request)
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can create Google Meet configuration.'
        );

        // Validate input
        $validated = $request->validate([
            'client_id' => 'required|string|max:191',
            'client_secret' => 'required|string|max:191',
            'redirect_uri' => 'required|url|max:191',
        ], [
            'client_id.required' => 'Google Client ID is required.',
            'client_secret.required' => 'Google Client Secret is required.',
            'redirect_uri.required' => 'Redirect URI is required.',
            'redirect_uri.url' => 'Redirect URI must be a valid URL.',
        ]);

        // XSS Prevention
        $validated['client_id'] = strip_tags($validated['client_id']);
        $validated['client_secret'] = strip_tags($validated['client_secret']);
        $validated['redirect_uri'] = strip_tags($validated['redirect_uri']);

        // Validate OAuth2 credentials format
        $validation = $this->oauthService->validateCredentials(
            $validated['client_id'],
            $validated['client_secret'],
            $validated['redirect_uri']
        );

        if (!$validation['valid']) {
            return redirect()
                ->back()
                ->withInput()
                ->with('error', implode(' ', $validation['errors']));
        }

        // Save configuration
        $config = $this->configService->saveConfiguration($validated);

        Log::info('Google Meet configuration created', [
            'user_id' => auth()->id(),
            'config_id' => $config->id,
        ]);

        return redirect()
            ->route('config.google-meet.index')
            ->with('success', 'Google Meet configuration saved successfully. Please authenticate with Google to complete setup.');
    }

    /**
     * Show the form for editing the configuration.
     *
     * @return \Illuminate\View\View
     */
    public function edit()
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can edit Google Meet configuration.'
        );

        $config = $this->configService->getConfiguration();

        if (!$config) {
            return redirect()
                ->route('config.google-meet.create')
                ->with('info', 'No configuration found. Please create one first.');
        }

        return view('config.google-meet.form', [
            'config' => $config,
            'isEdit' => true,
        ]);
    }

    /**
     * Update the configuration.
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(Request $request)
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can update Google Meet configuration.'
        );

        $config = $this->configService->getConfiguration();

        if (!$config) {
            return redirect()
                ->route('config.google-meet.create')
                ->with('info', 'No configuration found. Please create one first.');
        }

        // Validate input
        $validated = $request->validate([
            'client_id' => 'required|string|max:191',
            'client_secret' => 'required|string|max:191',
            'redirect_uri' => 'required|url|max:191',
        ], [
            'client_id.required' => 'Google Client ID is required.',
            'client_secret.required' => 'Google Client Secret is required.',
            'redirect_uri.required' => 'Redirect URI is required.',
            'redirect_uri.url' => 'Redirect URI must be a valid URL.',
        ]);

        // XSS Prevention
        $validated['client_id'] = strip_tags($validated['client_id']);
        $validated['client_secret'] = strip_tags($validated['client_secret']);
        $validated['redirect_uri'] = strip_tags($validated['redirect_uri']);

        // Validate OAuth2 credentials format
        $validation = $this->oauthService->validateCredentials(
            $validated['client_id'],
            $validated['client_secret'],
            $validated['redirect_uri']
        );

        if (!$validation['valid']) {
            return redirect()
                ->back()
                ->withInput()
                ->with('error', implode(' ', $validation['errors']));
        }

        // Update configuration
        $this->configService->updateConfiguration($config, $validated);

        Log::info('Google Meet configuration updated', [
            'user_id' => auth()->id(),
            'config_id' => $config->id,
        ]);

        return redirect()
            ->route('config.google-meet.index')
            ->with('success', 'Google Meet configuration updated successfully. Please re-authenticate with Google if credentials changed.');
    }

    /**
     * Redirect to Google OAuth2 consent screen.
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function authenticate()
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can authenticate with Google.'
        );

        $config = $this->configService->getConfiguration();

        if (!$config) {
            return redirect()
                ->route('config.google-meet.create')
                ->with('info', 'Please configure your Google OAuth2 credentials first.');
        }

        $authUrl = $this->oauthService->getAuthorizationUrl($config);

        Log::info('Redirecting to Google OAuth2 consent screen', [
            'user_id' => auth()->id(),
        ]);

        return redirect($authUrl);
    }

    /**
     * Handle OAuth2 callback from Google.
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function callback(Request $request)
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can complete Google authentication.'
        );

        // Check for error
        if ($request->has('error')) {
            $error = $request->get('error_description', $request->get('error'));
            
            Log::error('Google OAuth2 callback error', [
                'error' => $error,
                'user_id' => auth()->id(),
            ]);

            return redirect()
                ->route('config.google-meet.index')
                ->with('error', "Google authentication failed: {$error}");
        }

        // Validate authorization code
        if (!$request->has('code')) {
            return redirect()
                ->route('config.google-meet.index')
                ->with('error', 'No authorization code received from Google.');
        }

        try {
            $result = $this->oauthService->handleCallback(
                $request->get('code'),
                $request->get('state')
            );

            Log::info('Google OAuth2 authentication successful', [
                'user_id' => auth()->id(),
            ]);

            return redirect()
                ->route('config.google-meet.index')
                ->with('success', 'Successfully authenticated with Google! Your Google Meet integration is now ready to use.');
        } catch (\Exception $e) {
            Log::error('Google OAuth2 callback exception', [
                'error' => $e->getMessage(),
                'user_id' => auth()->id(),
            ]);

            return redirect()
                ->route('config.google-meet.index')
                ->with('error', "Authentication failed: {$e->getMessage()}");
        }
    }

    /**
     * Test the Google Meet API connection.
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
     */
    public function testConnection(Request $request)
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can test Google Meet connection.'
        );

        $config = $this->configService->getConfiguration();

        if (!$config) {
            return redirect()
                ->route('config.google-meet.create')
                ->with('info', 'Please configure your Google OAuth2 credentials first.');
        }

        // If POST request, perform the test
        if ($request->isMethod('post')) {
            $result = $this->meetProvider->testConnection($config);

            if ($result['success']) {
                return redirect()
                    ->route('config.google-meet.index')
                    ->with('success', "Connection test successful! {$result['message']}");
            }

            return redirect()
                ->route('config.google-meet.index')
                ->with('error', "Connection test failed: {$result['message']}");
        }

        // GET request - show test interface
        return view('config.google-meet.test', [
            'config' => $config,
            'status' => $this->configService->getStatusSummary(),
        ]);
    }

    /**
     * Test meeting creation.
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function testMeeting(Request $request)
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can test meeting creation.'
        );

        if (!$this->configService->isConfigured()) {
            return redirect()
                ->route('config.google-meet.create')
                ->with('info', 'Please configure your Google OAuth2 credentials first.');
        }

        $validated = $request->validate([
            'summary' => 'required|string|max:191',
            'start_time' => 'required|date|after:now',
            'end_time' => 'required|date|after:start_time',
            'attendees' => 'nullable|string',
        ], [
            'summary.required' => 'Meeting summary is required.',
            'start_time.required' => 'Start time is required.',
            'start_time.after' => 'Start time must be in the future.',
            'end_time.required' => 'End time is required.',
            'end_time.after' => 'End time must be after start time.',
        ]);

        // Parse attendees
        $attendees = [];
        if (!empty($validated['attendees'])) {
            $attendees = array_filter(
                array_map('trim', explode(',', $validated['attendees'])),
                fn($email) => filter_var($email, FILTER_VALIDATE_EMAIL)
            );
        }

        try {
            $result = $this->meetService->createMeeting(
                strip_tags($validated['summary']),
                $validated['start_time'],
                $validated['end_time'],
                $attendees
            );

            if ($result['success']) {
                return redirect()
                    ->route('config.google-meet.test')
                    ->with('success', "Test meeting created successfully!")
                    ->with('meeting_result', $result);
            }

            return redirect()
                ->route('config.google-meet.test')
                ->with('error', "Failed to create test meeting: {$result['message']}")
                ->withInput();
        } catch (\Exception $e) {
            return redirect()
                ->route('config.google-meet.test')
                ->with('error', "Error creating test meeting: {$e->getMessage()}")
                ->withInput();
        }
    }

    /**
     * Display meeting logs.
     *
     * @param Request $request
     * @return \Illuminate\View\View
     */
    public function logs(Request $request)
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can view meeting logs.'
        );

        $query = MeetingLog::query()->latest();

        // Filter by type
        if ($request->has('type') && !empty($request->type)) {
            $query->where('type', $request->type);
        }

        // Filter by status
        if ($request->has('status') && !empty($request->status)) {
            $query->where('status', $request->status);
        }

        // Filter by date range
        if ($request->has('date_from') && !empty($request->date_from)) {
            $query->whereDate('created_at', '>=', $request->date_from);
        }
        if ($request->has('date_to') && !empty($request->date_to)) {
            $query->whereDate('created_at', '<=', $request->date_to);
        }

        $logs = $query->paginate(20)->withQueryString();

        return view('config.google-meet.logs', compact('logs'));
    }

    /**
     * Display integration documentation.
     *
     * @return \Illuminate\View\View
     */
    public function documentation()
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can access documentation.'
        );

        return view('config.google-meet.documentation');
    }

    /**
     * Revoke Google OAuth access.
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function revokeAccess()
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can revoke Google access.'
        );

        $config = $this->configService->getConfiguration();

        if (!$config) {
            return redirect()
                ->route('config.google-meet.index')
                ->with('info', 'No configuration found to revoke.');
        }

        $this->oauthService->revokeAccess($config);

        Log::info('Google OAuth access revoked', [
            'user_id' => auth()->id(),
            'config_id' => $config->id,
        ]);

        return redirect()
            ->route('config.google-meet.index')
            ->with('success', 'Google access has been revoked. You will need to re-authenticate to use Google Meet features.');
    }

    /**
     * Delete the configuration.
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy()
    {
        abort_unless(
            auth()->user()->hasRole('Super Manager'),
            403,
            'Only Super Managers can delete Google Meet configuration.'
        );

        $this->configService->deleteConfiguration();

        Log::info('Google Meet configuration deleted', [
            'user_id' => auth()->id(),
        ]);

        return redirect()
            ->route('config.google-meet.index')
            ->with('success', 'Google Meet configuration has been deleted successfully.');
    }
}
