<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\ApiClientKey;
use App\Models\Device;
use App\Models\User;
use App\Services\FirebasePushService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

class AuthController extends Controller
{
    /**
     * Verify Firebase ID token and return Sanctum token
     */
    public function firebase(Request $request): JsonResponse
    {
        $request->validate([
            'id_token' => 'required|string',
            'device_id' => 'required|string',
            'platform' => 'required|string|in:android,ios,windows,macos,linux,web',
            'model' => 'nullable|string',
            'os_version' => 'nullable|string',
            'app_version' => 'nullable|string',
            'fcm_token' => 'nullable|string',
        ]);

        // Verify Firebase ID token via Firebase Auth REST API
        $firebaseProjectId = config('services.firebase.project_id');
        if (empty($firebaseProjectId)) {
            return response()->json(['error' => 'Firebase not configured', 'message' => 'Firebase is not configured on the server. Contact your admin.'], 500);
        }

        // Verify the Firebase ID token locally using Google's public RS256 certificates.
        // This does NOT require the Firebase Web API key and is unaffected by
        // API key domain/IP restrictions in Google Cloud Console.
        $claims = $this->verifyFirebaseIdToken($request->id_token, $firebaseProjectId);
        if ($claims === null) {
            return response()->json(['error' => 'Invalid Firebase token', 'message' => 'Invalid or expired Firebase token. Please sign in again.'], 401);
        }

        $firebaseUid = $claims['sub'];
        $email = $claims['email'] ?? null;
        $displayName = $claims['name'] ?? null;
        $photoUrl = $claims['picture'] ?? null;

        $user = User::firstOrCreate(
            ['firebase_uid' => $firebaseUid],
            [
                'name' => $displayName ?? Str::before($email, '@'),
                'email' => $email ?? $firebaseUid . '@firebase.local',
                'password' => bcrypt(Str::random(32)),
                'plan' => 'free',
                'avatar' => $photoUrl,
            ]
        );

        if ($user->is_banned) {
            return response()->json(['error' => 'Account suspended. Contact support.', 'message' => 'Account suspended. Contact support.'], 403);
        }

        $user->update(['last_seen_at' => now()]);

        // Upsert device record
        Device::updateOrCreate(
            ['device_id' => $request->device_id],
            [
                'user_id' => $user->id,
                'platform' => $request->platform,
                'model' => $request->model,
                'os_version' => $request->os_version,
                'app_version' => $request->app_version,
                'fcm_token' => $request->fcm_token,
                'is_revoked' => false,
            ]
        );

        // Send welcome push notification for newly registered users.
        if ($user->wasRecentlyCreated) {
            try {
                app(FirebasePushService::class)->sendFromTemplate('user_registered', $user);
            } catch (\Throwable) {
                // Never let a notification failure block the auth response.
            }
        }

        // Revoke old tokens for this device, issue new one
        $user->tokens()->where('name', 'device:' . $request->device_id)->delete();
        $token = $user->createToken('device:' . $request->device_id, ['sync'])->plainTextToken;
        [$apiKey, $plainApiKey] = ApiClientKey::issueForUser(
            $user,
            $request->device_id,
            $request->model ?: $request->device_id
        );

        return response()->json([
            'token' => $token,
            'api_key' => $plainApiKey,
            'api_key_meta' => [
                'id' => $apiKey->id,
                'prefix' => $apiKey->key_prefix,
                'rate_limit_per_minute' => $apiKey->rate_limit_per_minute,
                'rate_limit_per_day' => $apiKey->rate_limit_per_day,
            ],
            'user' => [
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
                'business_name' => $user->business_name,
                'plan' => $user->currentPlan(),
                'plan_expires_at' => $user->plan_expires_at,
                'storage_used_bytes' => $user->storage_used_bytes,
                'currency_code' => $user->currency_code,
                'country_code' => $user->country_code,
                'plan_details' => $user->currentPlanDetails(),
            ],
            'plan_catalog' => config('quickropos.plans'),
        ]);
    }

    /**
     * Get authenticated user profile
     */
    public function me(Request $request): JsonResponse
    {
        $user = $request->user();
        return response()->json([
            'user' => [
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
                'business_name' => $user->business_name,
                'phone' => $user->phone,
                'avatar' => $user->avatar,
                'plan' => $user->currentPlan(),
                'plan_expires_at' => $user->plan_expires_at,
                'storage_used_bytes' => $user->storage_used_bytes,
                'currency_code' => $user->currency_code,
                'country_code' => $user->country_code,
                'plan_details' => $user->currentPlanDetails(),
            ],
            'plan_catalog' => config('quickropos.plans'),
        ]);
    }

    /**
     * Revoke current device token (logout)
     */
    public function logout(Request $request): JsonResponse
    {
        $request->user()->currentAccessToken()->delete();
        return response()->json(['message' => 'Logged out']);
    }

    /**
     * V1: Request / refresh an API key for a POS device.
     * This is a public endpoint (no Bearer token required).
     * The device provides a Firebase ID token so the server can identify the user.
     *
     * Body: { id_token (required), device_id (required), platform?, device_name? }
     * Response: same as firebase() — includes api_key, token, user
     */
    public function requestApiKey(Request $request): JsonResponse
    {
        // Validate that id_token and device_id are present (firebase() validates the rest)
        $request->validate([
            'id_token'  => 'required|string',
            'device_id' => 'required|string',
        ]);

        // Delegate entirely to the existing firebase() method which handles
        // Firebase ID token verification, user creation, and API key issuance.
        return $this->firebase($request);
    }

    /**
     * Verify a Firebase ID token locally using Google's public RS256 certificates.
     *
     * Firebase ID tokens are RS256-signed JWTs. All the user data we need
     * (uid, email, name, picture) is in the payload — no external API call
     * required after the one-time cert fetch (which is cached for 1 hour).
     *
     * @return array<string, mixed>|null  Decoded JWT claims on success, null on failure.
     */
    private function verifyFirebaseIdToken(string $idToken, string $projectId): ?array
    {
        try {
            $parts = explode('.', $idToken);
            if (count($parts) !== 3) {
                return null;
            }
            [$headerB64, $payloadB64, $sigB64] = $parts;

            $header = json_decode($this->base64UrlDecode($headerB64), true);
            if (!isset($header['kid']) || ($header['alg'] ?? '') !== 'RS256') {
                return null;
            }

            // Fetch Google's public signing certs, cached for 1 hour.
            $certs = cache()->remember('firebase_token_certs', 3600, function () {
                $resp = Http::timeout(5)->get(
                    'https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com'
                );
                return $resp->successful() ? $resp->json() : null;
            });

            if (!is_array($certs) || !isset($certs[$header['kid']])) {
                return null;
            }

            $publicKey = openssl_pkey_get_public($certs[$header['kid']]);
            if (!$publicKey) {
                return null;
            }

            $signature = $this->base64UrlDecode($sigB64);
            $valid = openssl_verify(
                $headerB64 . '.' . $payloadB64,
                $signature,
                $publicKey,
                OPENSSL_ALGO_SHA256
            );
            if ($valid !== 1) {
                return null;
            }

            $claims = json_decode($this->base64UrlDecode($payloadB64), true);
            if (!is_array($claims)) {
                return null;
            }

            // Validate standard Firebase JWT claims.
            if (
                ($claims['iss'] ?? '') !== "https://securetoken.google.com/{$projectId}" ||
                ($claims['aud'] ?? '') !== $projectId ||
                ($claims['exp'] ?? 0) < time() ||
                empty($claims['sub'])
            ) {
                return null;
            }

            return $claims;
        } catch (\Throwable) {
            return null;
        }
    }

    private function base64UrlDecode(string $value): string
    {
        $remainder = strlen($value) % 4;
        if ($remainder) {
            $value .= str_repeat('=', 4 - $remainder);
        }
        return base64_decode(strtr($value, '-_', '+/'));
    }
}
