<?php
require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../utils/JWT.php';
require_once __DIR__ . '/../models/User.php';
require_once __DIR__ . '/../utils/SecurityLogger.php';
require_once __DIR__ . '/../utils/Cache.php';

class AuthController {
    private $db;

    public function __construct($database) {
        $this->db = $database;
    }

    public function login() {
        // Obtener datos del POST
        $data = json_decode(file_get_contents("php://input"), true);

        if (!$data || !isset($data['email']) || !isset($data['password'])) {
            http_response_code(400);
            return json_encode([
                'success' => false,
                'message' => 'Email y contraseña son requeridos'
            ]);
        }

        $email = trim($data['email']);
        $password = $data['password'];

        // Validar formato de email
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            http_response_code(400);
            return json_encode([
                'success' => false,
                'message' => 'Formato de email inválido'
            ]);
        }

        try {
            // Buscar usuario por email
            $user = new User($this->db);
            
            if (!$user->findByEmail($email)) {
                http_response_code(401);
                return json_encode([
                    'success' => false,
                    'message' => 'Credenciales inválidas'
                ]);
            }

            // Verificar contraseña
            if (!$user->verifyPassword($password)) {
                http_response_code(401);
                return json_encode([
                    'success' => false,
                    'message' => 'Credenciales inválidas'
                ]);
            }

            // Actualizar último acceso
            $user->updateLastAccess();

            // Invalidate user cache after login
            Cache::invalidateTag('user_' . $user->id);

            // Generar token JWT
            $payload = [
                'user_id' => $user->id,
                'email' => $user->email,
                'nombre' => $user->nombre,
                'rol' => $user->rol,
                'iat' => time(),
                'exp' => time() + JWT_EXPIRATION
            ];

            $token = JWT::encode($payload, JWT_SECRET, JWT_ALGORITHM);

            // Respuesta exitosa
            http_response_code(200);
            return json_encode([
                'success' => true,
                'message' => 'Login exitoso',
                'data' => [
                    'token' => $token,
                    'user' => [
                        'id' => $user->id,
                        'nombre' => $user->nombre,
                        'email' => $user->email,
                        'rol' => $user->rol
                    ]
                ]
            ]);

        } catch (Exception $e) {
            error_log("Error en login: " . $e->getMessage());
            http_response_code(500);
            return json_encode([
                'success' => false,
                'message' => 'Error interno del servidor'
            ]);
        }
    }

    public function logout() {
        // En JWT stateless, el logout se maneja en el cliente
        // Aquí podríamos implementar una blacklist de tokens si fuera necesario
        
        http_response_code(200);
        return json_encode([
            'success' => true,
            'message' => 'Logout exitoso'
        ]);
    }

    public function refresh() {
        try {
            // Obtener token del header Authorization
            $headers = getallheaders();
            $authHeader = isset($headers['Authorization']) ? $headers['Authorization'] : 
                         (isset($headers['authorization']) ? $headers['authorization'] : null);

            if (!$authHeader || !preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
                http_response_code(401);
                return json_encode([
                    'success' => false,
                    'message' => 'Token no proporcionado'
                ]);
            }

            $token = $matches[1];

            // Decodificar token actual
            $payload = JWT::decode($token, JWT_SECRET, JWT_ALGORITHM);

            // Verificar que el usuario aún existe y está activo
            $user = new User($this->db);
            if (!$user->findById($payload['user_id'])) {
                http_response_code(401);
                return json_encode([
                    'success' => false,
                    'message' => 'Usuario no válido'
                ]);
            }

            // Generar nuevo token
            $newPayload = [
                'user_id' => $user->id,
                'email' => $user->email,
                'nombre' => $user->nombre,
                'rol' => $user->rol,
                'iat' => time(),
                'exp' => time() + JWT_EXPIRATION
            ];

            $newToken = JWT::encode($newPayload, JWT_SECRET, JWT_ALGORITHM);

            http_response_code(200);
            return json_encode([
                'success' => true,
                'message' => 'Token renovado exitosamente',
                'data' => [
                    'token' => $newToken
                ]
            ]);

        } catch (Exception $e) {
            http_response_code(401);
            return json_encode([
                'success' => false,
                'message' => 'Token inválido o expirado'
            ]);
        }
    }

    public function me() {
        try {
            // Obtener usuario actual del middleware
            $currentUser = AuthMiddleware::getCurrentUser();

            if (!$currentUser) {
                http_response_code(401);
                return json_encode([
                    'success' => false,
                    'message' => 'No autenticado'
                ]);
            }

            // Try to get from cache first (5 minutes TTL)
            $cacheKey = "user_data_{$currentUser['user_id']}";
            $userData = Cache::get($cacheKey);

            if ($userData === null) {
                // Obtener datos actualizados del usuario
                $user = new User($this->db);
                if (!$user->findById($currentUser['user_id'])) {
                    http_response_code(404);
                    return json_encode([
                        'success' => false,
                        'message' => 'Usuario no encontrado'
                    ]);
                }

                $userData = [
                    'id' => $user->id,
                    'nombre' => $user->nombre,
                    'email' => $user->email,
                    'rol' => $user->rol,
                    'fecha_creacion' => $user->fecha_creacion,
                    'ultimo_acceso' => $user->ultimo_acceso
                ];

                // Cache with tags for easy invalidation (5 minutes TTL)
                Cache::tag(['users', 'user_' . $user->id], $cacheKey, $userData, 300);
            }

            http_response_code(200);
            return json_encode([
                'success' => true,
                'data' => [
                    'user' => $userData
                ]
            ]);

        } catch (Exception $e) {
            error_log("Error en me: " . $e->getMessage());
            http_response_code(500);
            return json_encode([
                'success' => false,
                'message' => 'Error interno del servidor'
            ]);
        }
    }

    public function changePassword() {
        try {
            // Obtener usuario actual
            $currentUser = AuthMiddleware::getCurrentUser();
            if (!$currentUser) {
                http_response_code(401);
                return json_encode([
                    'success' => false,
                    'message' => 'No autenticado'
                ]);
            }

            // Obtener datos del POST
            $data = json_decode(file_get_contents("php://input"), true);

            if (!$data || !isset($data['current_password']) || !isset($data['new_password'])) {
                http_response_code(400);
                return json_encode([
                    'success' => false,
                    'message' => 'Contraseña actual y nueva contraseña son requeridas'
                ]);
            }

            $currentPassword = $data['current_password'];
            $newPassword = $data['new_password'];

            // Validar longitud de nueva contraseña
            if (strlen($newPassword) < 6) {
                http_response_code(400);
                return json_encode([
                    'success' => false,
                    'message' => 'La nueva contraseña debe tener al menos 6 caracteres'
                ]);
            }

            // Obtener usuario de la base de datos
            $user = new User($this->db);
            if (!$user->findByEmail($currentUser['email'])) {
                http_response_code(404);
                return json_encode([
                    'success' => false,
                    'message' => 'Usuario no encontrado'
                ]);
            }

            // Verificar contraseña actual
            if (!$user->verifyPassword($currentPassword)) {
                http_response_code(400);
                return json_encode([
                    'success' => false,
                    'message' => 'Contraseña actual incorrecta'
                ]);
            }

            // Actualizar contraseña
            $query = "UPDATE usuarios SET password_hash = :password_hash WHERE id = :id";
            $stmt = $this->db->prepare($query);
            
            $hashedPassword = password_hash($newPassword, PASSWORD_BCRYPT);
            $stmt->bindParam(":password_hash", $hashedPassword);
            $stmt->bindParam(":id", $user->id);

            if ($stmt->execute()) {
                // Invalidate user cache after password change
                Cache::invalidateTag('user_' . $user->id);
                Cache::invalidateTag('users');
                
                http_response_code(200);
                return json_encode([
                    'success' => true,
                    'message' => 'Contraseña actualizada exitosamente'
                ]);
            } else {
                throw new Exception('Error al actualizar contraseña');
            }

        } catch (Exception $e) {
            error_log("Error en changePassword: " . $e->getMessage());
            http_response_code(500);
            return json_encode([
                'success' => false,
                'message' => 'Error interno del servidor'
            ]);
        }
    }
}
?>