<?php

namespace App\Http\Middleware;

use App\Models\User;
use App\Models\UserDevice;
use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AuthenticateApiToken
{
    /**
     * @param  Closure(Request): Response  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $token = $request->bearerToken();
        $apiKeyHeader = $request->header('ApiKey')
            ?? $request->header('apikey')
            ?? $request->header('X-API-KEY')
            ?? $request->header('x-api-key')
            ?? $request->input('api_key')
            ?? $request->input('apiKey');

        // 1. If Bearer token is provided
        if (is_string($token) && $token !== '') {
            $deviceIdHeader = $request->header('Device-Id');
            $hashedToken = hash('sha256', $token);

            // Match device by hashed or raw api_token
            $query = UserDevice::query()->with('user')
                ->where(function ($q) use ($token, $hashedToken) {
                    $q->where('api_token', $hashedToken)
                      ->orWhere('api_token', $token);
                });

            if (!empty($deviceIdHeader)) {
                $userDevice = (clone $query)->where('device_id', $deviceIdHeader)->first();
                if ($userDevice === null) {
                    $userDevice = $query->first();
                }
            } else {
                $userDevice = $query->first();
            }

            if ($userDevice !== null && $userDevice->user !== null) {
                if ($userDevice->status === 0) {
                    return new JsonResponse(['message' => 'This device has been deactivated. Please contact administrator.'], Response::HTTP_FORBIDDEN);
                }

                $userDevice->forceFill(['last_seen_at' => now()])->save();
                $user = $userDevice->user;
                $request->setUserResolver(fn (): User => $user);
                $request->attributes->set('user_device', $userDevice);

                return $next($request);
            }

            // Fallback: Check if Bearer token matches User's api_key directly
            $user = User::where('api_key', $token)->first();
            if ($user !== null) {
                if ($user->status === 0) {
                    return new JsonResponse(['message' => 'Your account is deactivated. Please contact administrator.'], Response::HTTP_FORBIDDEN);
                }
                $request->setUserResolver(fn (): User => $user);
                return $next($request);
            }
        }

        // 2. If ApiKey header or param is provided
        if (is_string($apiKeyHeader) && $apiKeyHeader !== '') {
            $user = User::where('api_key', $apiKeyHeader)->first();
            if ($user !== null) {
                if ($user->status === 0) {
                    return new JsonResponse(['message' => 'Your account is deactivated. Please contact administrator.'], Response::HTTP_FORBIDDEN);
                }
                $request->setUserResolver(fn (): User => $user);
                return $next($request);
            }
        }

        // 3. If authenticated via web session
        if (auth()->check()) {
            $user = auth()->user();
            $request->setUserResolver(fn (): User => $user);
            return $next($request);
        }

        return new JsonResponse(['message' => 'Authentication is required. Please provide a valid Bearer token or ApiKey.'], Response::HTTP_UNAUTHORIZED);
    }
}
