<?php

namespace App\Http\Controllers\SystemSettings;

use App\Helpers\SessionHelper;
use App\Services\Monitoring\SystemMonitoringService;
use App\Support\DataTable;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class SessionManagerController extends Controller
{
    public function __construct()
    {
        // Middleware handled in web.php
    }

    public function index(Request $request)
    {
        if (DataTable::isDataTableRequest($request)) {
            return $this->dataTable($request);
        }

        $stats = $this->getStatsData();

        return view('pages.system_settings.session-manager', compact('stats'));
    }

    protected function getDriver()
    {
        return config('session.driver');
    }

    public function getStats()
    {
        return response()->json($this->getStatsData());
    }

    protected function getStatsData()
    {
        $driver = $this->getDriver();

        if ($driver === 'database') {
            $activeCutoff = now()->subMinutes(30)->timestamp;

            return [
                'total' => DB::table('sessions')->count(),
                'active' => DB::table('sessions')->where('last_activity', '>=', $activeCutoff)->count(),
                'users' => DB::table('sessions')->whereNotNull('user_id')->count(),
                'guests' => DB::table('sessions')->whereNull('user_id')->count(),
                'unique_ips' => DB::table('sessions')->distinct('ip_address')->count('ip_address'),
            ];
        }

        if ($driver === 'redis') {
            $service = app(SystemMonitoringService::class);
            $total = $service->getActiveUsers();

            // For Redis, we'd need to iterate all to get specific user/guest breakdown
            // For performance, we'll return total for now or a limited set
            return [
                'total' => $total,
                'active' => $total,
                'users' => 'N/A (Redis)',
                'guests' => 'N/A (Redis)',
                'unique_ips' => 'N/A (Redis)',
            ];
        }

        return [
            'total' => 0, 'active' => 0, 'users' => 0, 'guests' => 0, 'unique_ips' => 0,
        ];
    }

    protected function dataTable(Request $request)
    {
        $driver = $this->getDriver();
        $sessions = [];
        $recordsTotal = 0;
        $recordsFiltered = 0;
        $activeCutoff = now()->subMinutes(30)->timestamp;
        $idleCutoff = now()->subMinutes(5)->timestamp;
        $currentSessionId = session()->getId();

        if ($driver === 'database') {
            $query = DB::table('sessions')
                ->leftJoin('users', 'sessions.user_id', '=', 'users.id')
                ->select(
                    'sessions.*',
                    'users.email as user_email',
                    'users.name as user_name'
                );

            $recordsTotal = DB::table('sessions')->count();

            // Status Filter
            if ($status = DataTable::columnSearch($request, 0)) {
                $operator = $status === 'active' ? '>=' : '<';
                $query->where('sessions.last_activity', $operator, $activeCutoff);
            }

            // User Filter
            if ($userSearch = DataTable::columnSearch($request, 1)) {
                $query->where(function ($q) use ($userSearch) {
                    $q->where('users.email', 'like', "%{$userSearch}%")
                        ->orWhere('users.name', 'like', "%{$userSearch}%");
                });
            }

            // IP Filter
            if ($ipSearch = DataTable::columnSearch($request, 3)) {
                $query->where('sessions.ip_address', 'like', "%{$ipSearch}%");
            }

            // Global Search
            if ($globalSearch = DataTable::globalSearch($request)) {
                $query->where(function ($q) use ($globalSearch) {
                    $q->where('users.email', 'like', "%{$globalSearch}%")
                        ->orWhere('users.name', 'like', "%{$globalSearch}%")
                        ->orWhere('sessions.id', 'like', "%{$globalSearch}%")
                        ->orWhere('sessions.ip_address', 'like', "%{$globalSearch}%");
                });
            }

            $recordsFiltered = (clone $query)->count();
            [$orderIndex, $orderDirection] = DataTable::order($request, 4, 'desc');

            $sortColumn = match ($orderIndex) {
                0 => 'sessions.last_activity',
                1 => 'users.name',
                3 => 'sessions.ip_address',
                4 => 'sessions.last_activity',
                default => 'sessions.last_activity',
            };

            $sessions = $query
                ->orderBy($sortColumn, $orderDirection)
                ->skip(DataTable::start($request))
                ->take(DataTable::length($request))
                ->get();
        } else {
            // REDIS DRIVER LOGIC
            $connection = config('session.connection') ?? 'default';
            $redis = Redis::connection($connection);
            $sessionCookie = config('session.cookie', 'laravel_session');
            $prefix = config('database.redis.options.prefix', '');

            // Optimization: Get keys once
            $patterns = [$sessionCookie.':*'];
            $keys = [];
            foreach ($patterns as $p) {
                $searchPattern = str_replace($prefix, '', $p);
                $keys = array_merge($keys, $redis->keys($searchPattern));
            }
            $keys = array_unique($keys);
            $recordsTotal = count($keys);
            $recordsFiltered = $recordsTotal;

            $start = DataTable::start($request);
            $length = DataTable::length($request);
            $pagedKeys = array_slice($keys, $start, $length);

            $tempSessions = [];
            $userIds = [];

            foreach ($pagedKeys as $key) {
                $pureKey = str_replace($prefix, '', $key);
                $data = $redis->get($pureKey);

                if ($data) {
                    try {
                        $unserialized = unserialize($data, ['allowed_classes' => false]);
                        if (is_string($unserialized)) {
                            $unserialized = unserialize($unserialized, ['allowed_classes' => false]);
                        }
                    } catch (\Exception $e) {
                        continue;
                    }

                    $parts = explode(':', $key);
                    $sessionId = end($parts);

                    if (isset($unserialized['user_id'])) {
                        $userIds[] = $unserialized['user_id'];
                    }

                    $tempSessions[] = [
                        'id' => $sessionId,
                        'user_id' => $unserialized['user_id'] ?? null,
                        'ip_address' => $unserialized['ip_address'] ?? 'N/A',
                        'user_agent' => $unserialized['user_agent'] ?? 'N/A',
                        'last_activity' => $unserialized['last_activity'] ?? time(),
                    ];
                }
            }

            // Batch fetch users to prevent N+1
            $users = ! empty($userIds) ? DB::table('users')->whereIn('id', array_unique($userIds))->get()->keyBy('id') : collect();

            foreach ($tempSessions as $sessData) {
                $user = $users->get($sessData['user_id']);
                $sessions[] = (object) array_merge($sessData, [
                    'user_name' => $user->name ?? 'Guest',
                    'user_email' => $user->email ?? 'N/A',
                ]);
            }
        }

        $rows = collect($sessions)->map(function ($session) use ($activeCutoff, $idleCutoff, $currentSessionId) {
            $isCurrent = $session->id === $currentSessionId;
            $userAgent = SessionHelper::parseUserAgent($session->user_agent);

            // Status Logic
            if ($isCurrent) {
                $statusHtml = '<span class="badge text-bg-success border border-success px-3 py-2 small fw-bold">
                                    <span class="spinner-grow spinner-grow-sm me-1" role="status"></span>'.__('LIVE').'
                               </span>';
            } elseif ($session->last_activity >= $idleCutoff) {
                $statusHtml = '<span class="badge text-bg-info px-3 py-2 small fw-bold">'.__('ACTIVE').'</span>';
            } elseif ($session->last_activity >= $activeCutoff) {
                $statusHtml = '<span class="badge text-bg-warning px-3 py-2 small fw-bold">'.__('IDLE').'</span>';
            } else {
                $statusHtml = '<span class="badge text-bg-secondary px-3 py-2 small">'.__('EXPIRED').'</span>';
            }

            // User Column
            $userHtml = '<div class="d-flex align-items-center">
                            <div>
                                <div class="fw-bold small">'.e($session->user_name ?? 'Guest').'</div>
                                <div class="text-secondary extra-small">'.e($session->user_email ?? substr($session->id, 0, 8).'...').'</div>
                            </div>
                         </div>';

            // Device Column
            $deviceHtml = '<div class="d-flex align-items-center">
                                <i class="bi '.$userAgent['browser_icon'].' h5 mb-0 me-2 text-theme-1"></i>
                                <div>
                                    <div class="small fw-medium">'.$userAgent['browser'].'</div>
                                    <div class="extra-small text-secondary"><i class="bi '.$userAgent['os_icon'].' me-1"></i>'.$userAgent['os'].'</div>
                                </div>
                           </div>';

            $timestamp = Carbon::createFromTimestamp($session->last_activity);

            $actionsHtml = '<div class="text-end d-flex justify-content-end gap-2">';
            $actionsHtml .= '<button class="btn btn-square btn-outline-theme btn-sm rounded-circle btn-detail-session" 
                                     data-activity=\''.e(json_encode([
                'session' => $session,
                'device' => $userAgent,
                'is_current' => $isCurrent,
                'time' => format_datetime($timestamp),
            ], JSON_HEX_APOS | JSON_HEX_QUOT)).'\'>
                                <i class="bi bi-eye"></i>
                             </button>';

            if (! $isCurrent) {
                if (auth()->user()->can('manage active sessions')) {
                    $actionsHtml .= '<button type="button" class="btn btn-square btn-outline-danger btn-sm rounded-circle btn-terminate-session" 
                                             data-id="'.e($session->id).'" 
                                             data-url="'.route('session-manager.terminate', $session->id).'">
                                        <i class="bi bi-x-lg"></i>
                                     </button>';
                } else {
                    $actionsHtml .= '<button class="btn btn-square btn-light btn-sm rounded-circle" disabled title="Insufficient permission">
                                        <i class="bi bi-shield-lock text-muted"></i>
                                     </button>';
                }
            } else {
                $actionsHtml .= '<button class="btn btn-square btn-light btn-sm rounded-circle" disabled title="Current session cannot be terminated">
                                    <i class="bi bi-lock-fill text-muted"></i>
                                 </button>';
            }
            $actionsHtml .= '</div>';

            return [
                $statusHtml,
                $userHtml,
                $deviceHtml,
                '<code class="extra-small">'.e($session->ip_address).'</code>',
                e($timestamp->diffForHumans()),
                $actionsHtml,
                $isCurrent, // For custom row coloring in JS
            ];
        })->all();

        return DataTable::response($request, $recordsTotal, $recordsFiltered, $rows);
    }

    public function destroy(Request $request, $id)
    {
        if ($id === session()->getId()) {
            return response()->json(['success' => false, 'message' => __('Cannot terminate current session.')], 403);
        }

        $driver = $this->getDriver();
        if ($driver === 'database') {
            DB::table('sessions')->where('id', $id)->delete();
        } elseif ($driver === 'redis') {
            $connection = config('session.connection') ?? 'default';
            $redis = Redis::connection($connection);
            $sessionCookie = config('session.cookie', 'laravel_session');
            $redis->del($sessionCookie.':'.$id);
        }

        return response()->json(['success' => true, 'message' => __('Session terminated successfully.')]);
    }
}
