<?php

namespace Plugin\UserOnlineDevices\Controllers;

use App\Http\Controllers\PluginController;
use App\Models\User;
use App\Services\DeviceStateService;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\URL;

class UserOnlineDevicesController extends PluginController
{
    public function __construct(
        private readonly DeviceStateService $deviceStateService
    ) {
    }

    public function summary(Request $request)
    {
        if ($error = $this->beforePluginAction()) {
            return $this->fail($error);
        }

        return $this->success($this->buildPayload($request->user()));
    }

    public function panelUrl(Request $request)
    {
        if ($error = $this->beforePluginAction()) {
            return $this->fail($error);
        }

        $user = $request->user();
        $ttlMinutes = max(1, (int) $this->getConfig('signed_url_ttl_minutes', 60));
        $expiresAt = now()->addMinutes($ttlMinutes);

        return $this->success([
            'url' => URL::temporarySignedRoute(
                'user-online-devices.panel',
                $expiresAt,
                ['user' => $user->id]
            ),
            'expires_at' => $expiresAt->timestamp,
        ]);
    }

    public function panel(Request $request, int $user): View
    {
        abort_unless($this->isPluginEnabled(), 404);

        $targetUser = User::query()->findOrFail($user);
        $payload = $this->buildPayload($targetUser);
        $ttlMinutes = max(1, (int) $this->getConfig('signed_url_ttl_minutes', 60));

        return view('UserOnlineDevices::panel', [
            'payload' => $payload,
            'snapshotUrl' => URL::temporarySignedRoute(
                'user-online-devices.snapshot',
                now()->addMinutes($ttlMinutes),
                ['user' => $targetUser->id]
            ),
            'refreshInterval' => max(5, (int) $this->getConfig('refresh_interval_seconds', 15)),
        ]);
    }

    public function snapshot(Request $request, int $user)
    {
        abort_unless($this->isPluginEnabled(), 404);

        $targetUser = User::query()->findOrFail($user);

        return response()->json([
            'data' => $this->buildPayload($targetUser),
        ]);
    }

    private function buildPayload(User $user): array
    {
        $devices = $this->deviceStateService->getUsersDevices([$user->id]);
        $ips = collect($devices[$user->id] ?? [])
            ->filter(fn ($ip) => is_string($ip) && $ip !== '')
            ->unique()
            ->values();

        return [
            'user' => [
                'id' => $user->id,
                'email' => $user->email,
                'online_count' => $ips->count(),
                'last_online_at' => $user->last_online_at,
            ],
            'online_devices' => $this->formatOnlineDevices($ips),
            'active_sessions' => $this->shouldShowActiveSessions()
                ? $this->formatActiveSessions($user)
                : [],
            'meta' => [
                'generated_at' => time(),
                'refresh_interval_seconds' => max(5, (int) $this->getConfig('refresh_interval_seconds', 15)),
                'mask_ip' => (bool) $this->getConfig('mask_ip', false),
                'show_active_sessions' => $this->shouldShowActiveSessions(),
            ],
        ];
    }

    private function formatOnlineDevices(Collection $ips): array
    {
        return $ips->values()->map(function (string $ip, int $index) {
            return [
                'name' => 'Device ' . ($index + 1),
                'ip' => $this->maskIp($ip),
                'raw_ip' => $ip,
            ];
        })->all();
    }

    private function formatActiveSessions(User $user): array
    {
        return $user->tokens()
            ->orderByDesc('last_used_at')
            ->get(['id', 'name', 'last_used_at', 'created_at', 'expires_at'])
            ->map(function ($token) {
                return [
                    'id' => $token->id,
                    'device' => $token->name ?: 'Unknown Session',
                    'last_used_at' => $token->last_used_at?->timestamp,
                    'created_at' => $token->created_at?->timestamp,
                    'expires_at' => $token->expires_at?->timestamp,
                ];
            })
            ->all();
    }

    private function shouldShowActiveSessions(): bool
    {
        return (bool) $this->getConfig('show_active_sessions', true);
    }

    private function maskIp(string $ip): string
    {
        if (!(bool) $this->getConfig('mask_ip', false)) {
            return $ip;
        }

        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            $parts = explode('.', $ip);
            $parts[3] = '*';
            return implode('.', $parts);
        }

        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            $parts = explode(':', $ip);
            $count = count($parts);
            if ($count > 2) {
                $parts[$count - 1] = '****';
                $parts[$count - 2] = '****';
            }
            return implode(':', $parts);
        }

        return $ip;
    }
}
