<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Configuration;
use App\Models\User;
use App\Models\UserDevice;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    /**
     * Check if app update is available.
     */
    public function checkUpdate(Request $request): JsonResponse
    {
        $currentVersion = (string) $request->query('version', $request->input('version', '1.0.0'));
        $platform = (string) $request->query('platform', $request->input('platform', 'android'));
        $appId = (string) $request->query('appId', $request->input('appId', 'com.tmssict.imikrof.epassbook'));

        $latestVersionConfig = Configuration::where('key', 'app_latest_version')->first();
        $minVersionConfig = Configuration::where('key', 'app_min_version')->first();
        $forceUpdateConfig = Configuration::where('key', 'app_force_update')->first();
        $playStoreUrlConfig = Configuration::where('key', 'app_play_store_url')->first();
        $releaseNotesConfig = Configuration::where('key', 'app_release_notes')->first();

        $latestVersion = $latestVersionConfig?->value ?: '1.0.0';
        $minVersion = $minVersionConfig?->value ?: '1.0.0';
        $forceUpdate = $forceUpdateConfig ? filter_var($forceUpdateConfig->value, FILTER_VALIDATE_BOOLEAN) : false;
        $playStoreUrl = $playStoreUrlConfig?->value ?: '';
        $releaseNotes = $releaseNotesConfig?->value ?: 'Performance improvements and stability fixes.';

        $updateAvailable = version_compare($currentVersion, $latestVersion, '<');
        $isForceUpdate = $forceUpdate || version_compare($currentVersion, $minVersion, '<');

        $payload = [
            'update_available' => $updateAvailable,
            'updateAvailable' => $updateAvailable,
            'latest_version' => $latestVersion,
            'latestVersion' => $latestVersion,
            'current_version' => $currentVersion,
            'currentVersion' => $currentVersion,
            'release_notes' => $releaseNotes,
            'releaseNotes' => $releaseNotes,
            'force_update' => $isForceUpdate,
            'forceUpdate' => $isForceUpdate,
            'play_store_url' => $playStoreUrl,
            'playStoreUrl' => $playStoreUrl,
            'min_required_version' => $minVersion,
            'minRequiredVersion' => $minVersion,
            'update_priority' => 0,
            'updatePriority' => 0,
            'app_id' => $appId,
            'appId' => $appId,
        ];

        return response()->json([
            'status' => 2000,
            'success' => true,
            'data' => $payload,
            'result' => $payload,
        ]);
    }
    /**
     * @throws ValidationException
     */
    public function login(Request $request){
        $headerDeviceId = $request->header('Device-Id');

        $validated = $request->validate([
            'email' => ['required', 'email', 'max:255'],
            'password' => ['required', 'string', 'max:255'],
            'device' => ['required', 'array'],
            'device.id' => [$headerDeviceId ? 'nullable' : 'required', 'string', 'max:255'],
            'device.name' => ['nullable', 'string', 'max:255'],
            'device.model' => ['nullable', 'string', 'max:255'],
            'device.platform' => ['nullable', 'string', 'max:32'],
            'device.operating_system' => ['nullable', 'string', 'max:32'],
            'device.os_version' => ['nullable', 'string', 'max:64'],
            'device.manufacturer' => ['nullable', 'string', 'max:255'],
            'device.is_virtual' => ['nullable', 'boolean'],
            'device.web_view_version' => ['nullable', 'string', 'max:255'],
            'device.app_version' => ['nullable', 'string', 'max:64'],
            'device.app_build' => ['nullable', 'string', 'max:64'],
            'device.locale' => ['nullable', 'string', 'max:35'],
            'device.fcm_token' => ['nullable', 'string'],
            'theme_mode' => ['nullable', 'string', Rule::in(['system', 'dark', 'light'])],
            'device.theme_mode' => ['nullable', 'string', Rule::in(['system', 'dark', 'light'])],
        ]);

        $authCheck = auth()->attempt([
            'email' => $validated['email'],
            'password' => $validated['password'],
        ]);

        if ($authCheck){
            /** @var User $user */
            $user = auth()->user();

            $themeMode = $request->input('theme_mode') ?? $request->input('device.theme_mode');
            if ($themeMode && in_array($themeMode, ['system', 'dark', 'light'], true)) {
                $user->update(['theme_mode' => $themeMode]);
                $user = $user->fresh();
            }

            $plainTextToken = Str::random(80);
            $device = $this->registerDevice($request, $user, $validated['device'], $plainTextToken);

            return response()->json([
                'data' => [
                    'token' => $plainTextToken,
                    'user' => $this->serializeUser($user),
                    'device' => $this->serializeDevice($device),
                ],
            ]);
        }

        throw ValidationException::withMessages([
            'email' => ['The provided email or password is incorrect.'],
        ]);
    }

    public function me(Request $request): JsonResponse
    {
        $user = $request->user();

        return response()->json(['data' => $this->serializeUser($user)]);
    }

    public function logout(Request $request): JsonResponse
    {
        /** @var UserDevice|null $device */
        $device = $request->attributes->get('user_device');
        $device?->forceFill([
            'api_token' => null,
            'last_logout_at' => now(),
        ])->save();

        return response()->json(['message' => 'Logged out successfully.']);
    }

    /**
     * @return array{id: int, name: string, email: string, locale: string, theme_mode: string}
     */
    private function serializeUser(User $user): array
    {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
            'contact_number' => $user->contact_number ?? $user->phone ?? null,
            'phone' => $user->contact_number ?? $user->phone ?? null,
            'locale' => $user->locale ?? 'en',
            'theme_mode' => $user->theme_mode ?? 'system',
        ];
    }

    /**
     * @param  array<string, mixed>  $metadata
     */
    private function registerDevice($request, $user, array $metadata, string $plainTextToken){
        $headerDeviceId = $request->header('Device-Id')
            ?? $request->header('device-id')
            ?? $request->header('device_id')
            ?? $request->header('Device-ID')
            ?? $request->header('X-Device-Id')
            ?? $request->header('x-device-id');

        $deviceIdString = !empty($headerDeviceId) ? $headerDeviceId : ($metadata['id'] ?? null);

        $data = [
            'device_id' => $deviceIdString,
            'name' => $metadata['name'] ?? null,
            'model' => $metadata['model'] ?? null,
            'platform' => $metadata['platform'] ?? null,
            'operating_system' => $metadata['operating_system'] ?? null,
            'os_version' => $metadata['os_version'] ?? null,
            'manufacturer' => $metadata['manufacturer'] ?? null,
            'is_virtual' => $metadata['is_virtual'] ?? false,
            'web_view_version' => $metadata['web_view_version'] ?? null,
            'app_version' => $metadata['app_version'] ?? null,
            'app_build' => $metadata['app_build'] ?? null,
            'locale' => $metadata['locale'] ?? null,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'api_token' => hash('sha256', $plainTextToken),
            'fcm_token' => $metadata['fcm_token'] ?? null,
            'last_login_at' => now(),
            'last_seen_at' => now(),
            'last_logout_at' => null,
            'status' => 1,
        ];

        $userDevice = null;
        if (!empty($deviceIdString)) {
            $userDevice = UserDevice::where('user_id', $user->id)
                ->where('device_id', $deviceIdString)
                ->first();
        }

        if (!$userDevice && !empty($metadata['id'])) {
            $userDevice = UserDevice::where('user_id', $user->id)
                ->where('device_id', $metadata['id'])
                ->first();
        }

        if (!$userDevice){
            $userDevice = new UserDevice();
        }

        $userDevice->fill($data);
        $userDevice->device_id = $deviceIdString;
        $userDevice->user_id = $user->id;
        $userDevice->save();

        return $userDevice;
    }

    /**
     * @return array<string, mixed>
     */
    private function serializeDevice(UserDevice $device): array
    {
        return [
            'id' => $device->id,
            'device_id' => $device->device_id,
            'name' => $device->name,
            'model' => $device->model,
            'platform' => $device->platform,
            'operating_system' => $device->operating_system,
            'os_version' => $device->os_version,
            'manufacturer' => $device->manufacturer,
            'app_version' => $device->app_version,
            'app_build' => $device->app_build,
            'last_login_at' => $device->last_login_at,
        ];
    }
}
