<?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Api\Core\BaseApiController;
use App\Models\User;
use App\Services\Auth\ApiLoginSecurityService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use PHPOpenSourceSaver\JWTAuth\Facades\JWTAuth;

class AuthController extends BaseApiController
{
    public function login(Request $request, ApiLoginSecurityService $security): JsonResponse
    {
        $payload = $request->all();
        if ($request->isJson() && ($payload === [] || $payload === null)) {
            $decoded = json_decode((string) $request->getContent(), true);
            $payload = is_array($decoded) ? $decoded : [];
        }

        $email = strtolower(trim((string) ($payload['email'] ?? '')));
        $password = (string) ($payload['password'] ?? '');

        if ($email === '' || $password === '') {
            return response()->json([
                'status' => false,
                'message' => 'Email and password are required.',
            ], 400);
        }

        $ip = $request->ip();
        if ($security->isIpBlocked((string) $ip)) {
            return response()->json([
                'status' => false,
                'message' => 'Too many failed attempts from your IP. Please try again later.',
            ], 429);
        }

        $user = User::query()->whereRaw('LOWER(email) = ?', [$email])->first();
        if (!$user) {
            $security->logIpAttempt((string) $ip);

            return response()->json([
                'status' => false,
                'message' => 'Invalid email or password.',
            ], 401);
        }

        if (! verify_stored_password($password, (string) $user->password)) {
            $security->handleFailedLogin($user, $email, (string) $ip);

            return response()->json([
                'status' => false,
                'message' => 'Invalid email or password.',
            ], 401);
        }

        // Suspension is checked AFTER credentials are verified so that the
        // response shape cannot be used to enumerate which emails exist.
        if ($user->is_suspended) {
            return response()->json([
                'status' => false,
                'message' => 'Account suspended. Please reset your password.',
            ], 403);
        }

        $security->resetFailedAttempts($user);
        $security->logSuccessfulLogin($user->fresh(), $request);

        $fresh = $user->fresh();
        if (!$fresh) {
            return response()->json([
                'status' => false,
                'message' => 'Invalid email or password.',
            ], 401);
        }

        $jwtToken = JWTAuth::fromUser($fresh);

        return response()->json($security->buildLoginResponse($fresh, $jwtToken));
    }

    public function refresh(Request $request): JsonResponse
    {
        try {
            $newToken = JWTAuth::parseToken()->refresh();
        } catch (\Throwable $e) {
            return $this->respondError('Token refresh failed.', 401);
        }

        return $this->respondSuccess([
            'access_token' => $newToken,
            'token_type' => 'bearer',
            'expires_in' => (int) config('jwt.ttl') * 60,
        ], 'Token refreshed.');
    }

    public function me(): JsonResponse
    {
        $user = Auth::user();
        if (!$user) {
            return $this->respondError('Unauthorized.', 401);
        }

        $teacherContext = $user->teacherSessionContext();

        return $this->respondSuccess([
            'id' => (int) $user->id,
            'firstname' => $user->firstname,
            'lastname' => $user->lastname,
            'email' => $user->email,
            'class_section_id' => $teacherContext['class_section_id'],
            'class_section_name' => $teacherContext['class_section_name'],
        ], 'OK');
    }

    public function logout(Request $request): JsonResponse
    {
        $token = $request->bearerToken();
        if ($token && substr_count($token, '.') === 2) {
            try {
                JWTAuth::setToken($token)->invalidate();
            } catch (\Throwable $e) {
                // ignore invalidation errors
            }
        }

        $user = $request->user();
        if ($user && method_exists($user, 'currentAccessToken')) {
            $current = $user->currentAccessToken();
            if ($current) {
                $current->delete();
            }
        }

        return $this->respondSuccess(null, 'Logged out.');
    }
}
