<?php

namespace App\Http\Controllers;

use App\Services\ApiService;
use App\Services\UserService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Log;

class AuthController extends Controller
{
    protected $apiService;
    protected $userService;

    public function __construct(ApiService $apiService, UserService $userService)
    {
        $this->apiService = $apiService;
        $this->userService = $userService;
    }

    /**
     * Mostrar formulario de login
     */
    public function showLoginForm()
    {
        // Verificar si tiene una sesión válida pero expirada
        if (session('backoffice_authenticated')) {
            $lastActivity = session('backoffice_last_activity');
            $sessionLifetime = config('backoffice.session.lifetime', 120) * 60; // convertir a segundos
            
            // Si la sesión ha expirado, limpiarla completamente
            if ($lastActivity && (time() - $lastActivity) > $sessionLifetime) {
                Log::warning('Expired session cleared on login form access', [
                    'username' => session('backoffice_user', 'unknown'),
                    'last_activity' => date('Y-m-d H:i:s', $lastActivity),
                    'inactivity_minutes' => round((time() - $lastActivity) / 60, 2),
                ]);
                
                Session::invalidate();
                Session::regenerateToken();
                
                return view('auth.login')->with('error', 'Tu sesión anterior ha expirado. Por favor, inicia sesión nuevamente.');
            }
            
            // Si la sesión sigue válida, redirigir al dashboard
            return redirect()->route('dashboard');
        }

        return view('auth.login');
    }

    /**
     * Procesar login
     */
    public function login(Request $request)
    {
        $request->validate([
            'username' => 'required|string',
            'password' => 'required|string',
        ]);

        $username = $request->input('username');
        $password = $request->input('password');
        $clientIp = $this->getClientIp($request);

        // Verificar intento de login previo (protección contra fuerza bruta)
        $maxAttempts = config('backoffice.admin.max_login_attempts', 3);
        $lockoutDuration = config('backoffice.admin.lockout_duration', 300); // 5 minutos
        $lockoutKey = 'backoffice_lockout_' . $clientIp;

        if (Session::has($lockoutKey)) {
            $lockoutTime = Session::get($lockoutKey);
            if (time() - $lockoutTime < $lockoutDuration) {
                $remainingTime = $lockoutDuration - (time() - $lockoutTime);
                
                Log::warning('Login attempt during lockout', [
                    'username' => $username,
                    'ip' => $clientIp,
                    'remaining_lockout_seconds' => $remainingTime,
                ]);

                return back()->withErrors([
                    'error' => "Demasiados intentos fallidos. Intenta nuevamente en {$remainingTime} segundos."
                ])->withInput();
            } else {
                // Lockout expirado, limpiar
                Session::forget($lockoutKey);
                Session::forget('backoffice_login_attempts');
            }
        }

        // Intentar autenticación a través del API primero
        try {
            $authResult = $this->userService->authenticate($username, $password);
            
            if ($authResult) {
                // Login exitoso con API
                $userType = $authResult['user_type'] ?? 'regular';
                $userData = $authResult['user'] ?? null;
                $displayName = $this->getDisplayName($userData, $userType);
                
                Session::put('backoffice_authenticated', true);
                Session::put('backoffice_user', $displayName);
                Session::put('backoffice_user_type', $userType);
                Session::put('backoffice_login_time', now());
                Session::put('backoffice_last_activity', time());
                Session::put('backoffice_token', $authResult['token'] ?? null);
                Session::put('user_data', $userData);
                Session::put('user_permissions', $authResult['permissions'] ?? []);

                // Configurar token en el ApiService para futuras peticiones
                if (isset($authResult['token'])) {
                    $this->apiService->setToken($authResult['token']);
                }

                // Limpiar intentos fallidos
                Session::forget('backoffice_login_attempts');
                Session::forget($lockoutKey);

                // Regenerar session ID por seguridad
                Session::regenerate();

                Log::info('Login successful via API', [
                    'username' => $username,
                    'user_type' => $userType,
                    'display_name' => $displayName,
                    'ip' => $clientIp,
                    'login_time' => now(),
                    'user_agent' => $request->userAgent(),
                ]);

                return redirect()->route('dashboard');
            }
        } catch (\Exception $e) {
            Log::error('API authentication error', [
                'username' => $username,
                'ip' => $clientIp,
                'error' => $e->getMessage(),
            ]);
        }

        // Login fallido
        $attempts = Session::get('backoffice_login_attempts', 0) + 1;
        Session::put('backoffice_login_attempts', $attempts);

        Log::warning('Login failed', [
            'username' => $username,
            'ip' => $clientIp,
            'attempt_number' => $attempts,
            'user_agent' => $request->userAgent(),
        ]);

        if ($attempts >= $maxAttempts) {
            // Activar lockout
            Session::put($lockoutKey, time());
            Session::forget('backoffice_login_attempts');

            Log::warning('Account locked due to multiple failed attempts', [
                'username' => $username,
                'ip' => $clientIp,
                'lockout_duration_seconds' => $lockoutDuration,
            ]);

            return back()->withErrors([
                'error' => "Demasiados intentos fallidos. Cuenta bloqueada por {$lockoutDuration} segundos."
            ])->withInput();
        }

        return back()->withErrors([
            'error' => 'Credenciales incorrectas. Intentos restantes: ' . ($maxAttempts - $attempts)
        ])->withInput();
    }

    /**
     * Logout
     */
    public function logout(Request $request)
    {
        $username = session('backoffice_user');
        $loginTime = session('backoffice_login_time');
        $sessionDuration = $loginTime ? now()->diffInMinutes($loginTime) : 0;

        Log::info('Logout', [
            'username' => $username,
            'session_duration_minutes' => $sessionDuration,
            'logout_time' => now(),
        ]);

        // Intentar logout del API si existe token
        try {
            $token = Session::get('backoffice_token');
            if ($token) {
                $this->apiService->setToken($token);
                $this->apiService->makeApiRequest('POST', api_url('auth.logout'), [], [], 'user_logout');
            }
        } catch (\Exception $e) {
            Log::warning('API logout error', ['error' => $e->getMessage()]);
        }

        // Limpiar todas las variables de sesión del backoffice
        Session::forget('backoffice_authenticated');
        Session::forget('backoffice_user');
        Session::forget('backoffice_user_type');
        Session::forget('backoffice_login_time');
        Session::forget('backoffice_last_activity');
        Session::forget('backoffice_token');
        Session::forget('user_data');
        Session::forget('user_permissions');

        // Invalidar toda la sesión por seguridad
        Session::invalidate();
        Session::regenerateToken();

        return redirect()->route('login')->with('message', 'Sesión cerrada correctamente.');
    }

    /**
     * Verificar si está autenticado (middleware helper)
     */
    public function checkAuth()
    {
        if (!session('backoffice_authenticated')) {
            return response()->json(['authenticated' => false], 401);
        }

        return response()->json([
            'authenticated' => true,
            'user' => session('backoffice_user'),
            'login_time' => session('backoffice_login_time'),
        ]);
    }

    /**
     * Obtener información de la sesión actual
     */
    public function sessionInfo()
    {
        if (!session('backoffice_authenticated')) {
            return response()->json(['error' => 'No authenticated'], 401);
        }

        $loginTime = session('backoffice_login_time');
        $lastActivity = session('backoffice_last_activity');

        return response()->json([
            'user' => session('backoffice_user'),
            'login_time' => $loginTime,
            'session_duration_minutes' => $loginTime ? now()->diffInMinutes($loginTime) : 0,
            'last_activity' => $lastActivity ? date('Y-m-d H:i:s', $lastActivity) : null,
            'session_expires_in_minutes' => config('backoffice.session.lifetime', 240),
        ]);
    }

    /**
     * Obtener IP real del cliente considerando proxies y CDNs
     */
    private function getClientIp(Request $request): string
    {
        return $request->header('CF-Connecting-IP') 
            ?? $request->header('X-Real-IP')
            ?? $request->header('X-Forwarded-For')
            ?? $request->ip();
    }

    /**
     * Obtener nombre para mostrar según el tipo de usuario
     */
    private function getDisplayName(?array $userData, string $userType): string
    {
        if (!$userData) {
            return 'Usuario';
        }

        switch ($userType) {
            case 'advisor':
                $name = ($userData['name'] ?? '') . ' ' . ($userData['last_name'] ?? '');
                return trim($name) ?: ($userData['email'] ?? 'Asesor Comercial');
                
            case 'regular':
                return $userData['name'] ?? $userData['username'] ?? $userData['email'] ?? 'Usuario';
                
            case 'admin':
            default:
                return $userData['name'] ?? 'Administrador';
        }
    }
}