<?php

use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
use Livewire\Attributes\Title;
use Livewire\Volt\Component;

new #[Title('Browser Sessions')] class extends Component {
    public array $sessions = [];
    public bool $canManageSessions = false;
    public bool $locationEnabled = false;
    protected string $sessionTable = 'sessions';

    public function mount(): void
    {
        $this->sessionTable = config('session.table', 'sessions');
        $this->canManageSessions = config('session.driver') === 'database' && Schema::hasTable($this->sessionTable);
        $this->locationEnabled = (bool) config('services.geoip.enabled', false);

        $this->sessions = $this->buildSessions();
    }

    public function refreshSessions(): void
    {
        $this->sessions = $this->buildSessions();
    }

    public function revokeSession(string $encodedId): void
    {
        if (! $this->canManageSessions) {
            return;
        }

        $sessionId = base64_decode($encodedId, true);

        if ($sessionId === false) {
            return;
        }

        DB::table($this->sessionTable)
            ->where('user_id', Auth::id())
            ->where('id', $sessionId)
            ->delete();

        $this->refreshSessions();
        $this->dispatch('session-revoked');
    }

    public function revokeOtherSessions(): void
    {
        if (! $this->canManageSessions) {
            return;
        }

        DB::table($this->sessionTable)
            ->where('user_id', Auth::id())
            ->where('id', '!=', session()->getId())
            ->delete();

        $this->refreshSessions();
        $this->dispatch('sessions-cleared');
    }

    protected function buildSessions(): array
    {
        return $this->sessionRecords()
            ->map(fn (object $session) => $this->formatSession($session))
            ->values()
            ->all();
    }

    protected function sessionRecords(): \Illuminate\Support\Collection
    {
        if ($this->canManageSessions) {
            return DB::table($this->sessionTable)
                ->where('user_id', Auth::id())
                ->orderByDesc('last_activity')
                ->get();
        }

        return collect([$this->currentSessionFallback()]);
    }

    protected function currentSessionFallback(): object
    {
        return (object) [
            'id' => session()->getId(),
            'ip_address' => request()?->ip(),
            'user_agent' => request()?->userAgent(),
            'last_activity' => now()->timestamp,
        ];
    }

    protected function formatSession(object $session): array
    {
        $agent = $this->parseUserAgent($session->user_agent ?? '');
        $location = $this->locationEnabled ? $this->resolveLocation($session->ip_address) : null;

        return [
            'id' => $session->id,
            'reference' => base64_encode($session->id),
            'ip_address' => $session->ip_address ?: __('Unknown'),
            'browser' => $agent['browser'],
            'platform' => $agent['platform'],
            'device' => $agent['device'],
            'is_current_device' => $session->id === session()->getId(),
            'last_active' => Carbon::createFromTimestamp((int) ($session->last_activity ?? now()->timestamp))->diffForHumans(),
            'location' => $location,
        ];
    }

    protected function parseUserAgent(?string $userAgent): array
    {
        $browser = 'Unknown';
        $platform = 'Unknown';
        $device = 'Desktop';

        $ua = Str::lower($userAgent ?? '');

        if ($ua === '') {
            return compact('browser', 'platform', 'device');
        }

        if (Str::contains($ua, 'edg')) {
            $browser = 'Microsoft Edge';
        } elseif (Str::contains($ua, ['opr', 'opera'])) {
            $browser = 'Opera';
        } elseif (Str::contains($ua, 'chrome')) {
            $browser = 'Google Chrome';
        } elseif (Str::contains($ua, 'firefox')) {
            $browser = 'Mozilla Firefox';
        } elseif (Str::contains($ua, 'safari')) {
            $browser = 'Safari';
        } elseif (Str::contains($ua, ['msie', 'trident'])) {
            $browser = 'Internet Explorer';
        }

        if (Str::contains($ua, ['iphone', 'ipod'])) {
            $platform = 'iOS';
            $device = 'Mobile';
        } elseif (Str::contains($ua, 'ipad')) {
            $platform = 'iPadOS';
            $device = 'Tablet';
        } elseif (Str::contains($ua, 'android')) {
            $platform = 'Android';
            $device = Str::contains($ua, 'mobile') ? 'Mobile' : 'Tablet';
        } elseif (Str::contains($ua, 'windows')) {
            $platform = 'Windows';
            $device = 'Desktop';
        } elseif (Str::contains($ua, ['macintosh', 'mac os x'])) {
            $platform = 'macOS';
            $device = 'Desktop';
        } elseif (Str::contains($ua, 'linux')) {
            $platform = 'Linux';
            $device = 'Desktop';
        }

        return compact('browser', 'platform', 'device');
    }

    protected function resolveLocation(?string $ip): ?string
    {
        if (! $this->locationEnabled) {
            return null;
        }

        if (! $ip || ! filter_var($ip, FILTER_VALIDATE_IP) || ! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            return null;
        }

        $cacheKey = sprintf('browser-session-location-%s', $ip);
        $ttl = (int) config('services.geoip.cache_ttl', 86400);
        $ttl = $ttl > 0 ? $ttl : 86400;

        return Cache::remember($cacheKey, now()->addSeconds($ttl), function () use ($ip) {
            try {
                $endpoint = str_replace('{ip}', $ip, config('services.geoip.endpoint', 'https://ipapi.co/{ip}/json/'));

                $request = Http::timeout((int) config('services.geoip.timeout', 3));

                if ($token = config('services.geoip.token')) {
                    $request = $request->withToken($token);
                }

                $response = $request->get($endpoint);

                if (! $response->successful()) {
                    return null;
                }

                $data = $response->json();

                if (! empty($data['error'])) {
                    return null;
                }

                $segments = collect([
                    $data['city'] ?? null,
                    $data['region'] ?? null,
                    $data['country_name'] ?? null,
                ])->filter()->implode(', ');

                return $segments ?: null;
            } catch (\Throwable) {
                return null;
            }
        });
    }
};
?>

<section class="w-full">
    @include('partials.settings-heading')

    <x-settings.layout
        :heading="__('Browser Sessions')"
        :subheading="__('Review devices that have accessed your account and revoke anything you do not recognize.')"
        content-width="max-w-3xl"
    >
        <div class="mt-6 space-y-4">
            @unless ($canManageSessions)
                <div class="rounded-md border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">
                    {{ __('Browser session management requires the session driver to be set to the database driver.') }}
                </div>
            @endunless

            @forelse ($sessions as $session)
                <div class="rounded-xl border border-neutral-200 bg-white p-5 shadow-sm transition hover:-translate-y-0.5 hover:shadow-md dark:border-neutral-700 dark:bg-gray-900/90 dark:text-white">
                    <div class="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
                        <div class="space-y-3 text-sm">
                            <div class="flex flex-wrap items-center gap-2 text-base font-semibold text-slate-900 dark:text-white">
                                <span>{{ $session['browser'] }}</span>
                                <span class="text-slate-300 dark:text-slate-500">•</span>
                                <span>{{ $session['platform'] }}</span>
                            </div>

                            <div class="flex flex-wrap items-center gap-3 text-xs font-medium uppercase tracking-wide text-slate-600 dark:text-slate-300">
                                <span class="inline-flex items-center rounded-md bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-600 dark:bg-slate-700 dark:text-slate-100">
                                    {{ $session['device'] }}
                                </span>
                                <span class="text-xs normal-case text-slate-500 dark:text-slate-300">{{ __('IP: :ip', ['ip' => $session['ip_address']]) }}</span>
                            </div>

                            @if ($locationEnabled && $session['location'])
                                <div class="text-sm text-slate-500 dark:text-slate-300">
                                    {{ __('Location: :location', ['location' => $session['location']]) }}
                                </div>
                            @endif

                            <div class="text-xs text-slate-400 dark:text-slate-400">
                                {{ __('Last active :time', ['time' => $session['last_active']]) }}
                            </div>
                        </div>

                        <div class="flex items-center gap-3 md:flex-col md:items-end md:gap-2">
                            @if ($session['is_current_device'])
                                <span class="inline-flex items-center rounded-full bg-emerald-500/95 px-3 py-1 text-xs font-semibold text-white">
                                    {{ __('Current device') }}
                                </span>
                            @elseif ($canManageSessions)
                                <flux:button
                                    wire:click="revokeSession('{{ $session['reference'] }}')"
                                    class="primary !bg-indigo-700 !text-white hover:!bg-indigo-500 dark:!bg-slate-800 dark:hover:!bg-slate-700 dark:!text-white"
                                >
                                    {{ __('Revoke') }}
                                </flux:button>
                            @endif
                        </div>
                    </div>
                </div>
            @empty
                <div class="rounded-xl border border-dashed border-slate-200/70 bg-white/80 p-6 text-center text-sm text-slate-500 dark:border-slate-800/50 dark:bg-slate-800/70 dark:text-slate-300">
                    {{ __('No browser sessions recorded yet.') }}
                </div>
            @endforelse
        </div>

        @if ($canManageSessions && count($sessions) > 1)
            <div class="mt-6 flex flex-wrap items-center gap-4">
                <flux:button
                    wire:click="revokeOtherSessions"
                    class="primary !bg-indigo-700 !text-white hover:!bg-indigo-500"
                >
                    {{ __('Log out all sessions') }}
                </flux:button>

                <x-action-message class="text-sm text-green-600 dark:text-green-400" on="sessions-cleared">
                    {{ __('Sessions cleared.') }}
                </x-action-message>
            </div>
        @endif

        <x-action-message class="mt-4 text-sm text-green-600 dark:text-green-400" on="session-revoked">
            {{ __('Session revoked.') }}
        </x-action-message>
    </x-settings.layout>
</section>
