<?php

namespace App\Http\Controllers;

use App\Helpers\Helper;
use App\Models\User;
use App\Models\UserDevice;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class UserDeviceController extends Controller
{
    use Helper;

    public function __construct()
    {
        $this->model = new UserDevice();
    }

    /**
     * Display a listing of user devices with filters and summary analytics.
     */
    public function index()
    {
        try {
            $keyword    = request()->input('keyword');
            $userId     = request()->input('user_id');
            $status     = request()->input('status');
            $platform   = request()->input('platform');
            $isVirtual  = request()->input('is_virtual');
            $perPage    = request()->input('perPage', 20);

            $query = UserDevice::query()->with(['user:id,name,email,contact_number,phone,company_name']);

            // User filter (Superadmin can filter by user; regular user only sees their devices)
            $authUser = auth()->user();
            if ($authUser && !$authUser->is_superadmin && $authUser->role_id != 1) {
                $query->where('user_id', $authUser->id);
            } elseif ($userId && $userId !== 'all') {
                $query->where('user_id', $userId);
            }

            // Keyword filter
            if ($keyword) {
                $query->where(function ($q) use ($keyword) {
                    $q->where('name', 'LIKE', "%{$keyword}%")
                      ->orWhere('model', 'LIKE', "%{$keyword}%")
                      ->orWhere('manufacturer', 'LIKE', "%{$keyword}%")
                      ->orWhere('device_id', 'LIKE', "%{$keyword}%")
                      ->orWhere('platform', 'LIKE', "%{$keyword}%")
                      ->orWhere('operating_system', 'LIKE', "%{$keyword}%")
                      ->orWhere('os_version', 'LIKE', "%{$keyword}%")
                      ->orWhere('app_version', 'LIKE', "%{$keyword}%")
                      ->orWhere('ip_address', 'LIKE', "%{$keyword}%")
                      ->orWhere('user_agent', 'LIKE', "%{$keyword}%")
                      ->orWhereHas('user', function ($uq) use ($keyword) {
                          $uq->where('name', 'LIKE', "%{$keyword}%")
                             ->orWhere('email', 'LIKE', "%{$keyword}%");
                      });
                });
            }

            // Status filter
            if ($status !== null && $status !== '') {
                $query->where('status', (int)$status);
            }

            // Platform filter
            if ($platform && $platform !== 'all') {
                $query->where('platform', strtolower($platform));
            }

            // Virtual/Emulator filter
            if ($isVirtual !== null && $isVirtual !== '') {
                $query->where('is_virtual', (bool)$isVirtual);
            }

            // Date Range
            if (request()->filled('from_date')) {
                $query->whereDate('created_at', '>=', request('from_date'));
            }
            if (request()->filled('to_date')) {
                $query->whereDate('created_at', '<=', request('to_date'));
            }

            // Summary Stats Query
            $statsQuery = UserDevice::query();
            if ($authUser && !$authUser->is_superadmin && $authUser->role_id != 1) {
                $statsQuery->where('user_id', $authUser->id);
            } elseif ($userId && $userId !== 'all') {
                $statsQuery->where('user_id', $userId);
            }

            $fifteenMinsAgo = Carbon::now()->subMinutes(15);
            $twentyFourHoursAgo = Carbon::now()->subHours(24);

            $stats = (clone $statsQuery)->selectRaw("
                COUNT(id) as total,
                COUNT(CASE WHEN status = 1 THEN 1 END) as active,
                COUNT(CASE WHEN status = 0 THEN 1 END) as inactive,
                COUNT(CASE WHEN last_seen_at >= ? THEN 1 END) as online,
                COUNT(CASE WHEN last_seen_at >= ? THEN 1 END) as active_24h,
                COUNT(CASE WHEN LOWER(platform) = 'android' THEN 1 END) as android,
                COUNT(CASE WHEN LOWER(platform) = 'ios' THEN 1 END) as ios,
                COUNT(CASE WHEN is_virtual = 1 THEN 1 END) as is_virtual_count
            ", [$fifteenMinsAgo, $twentyFourHoursAgo])->first();

            $devices = $query->withCount([
                'smsMessages as total_messages',
                'smsMessages as sent_messages' => function ($q) {
                    $q->where('status', 'sent');
                },
                'smsMessages as failed_messages' => function ($q) {
                    $q->where('status', 'failed');
                },
            ])
            ->orderBy('last_seen_at', 'desc')
            ->orderBy('id', 'desc')
            ->paginate((int)$perPage);

            // Format records with helper tags
            $devices->getCollection()->transform(function ($device) use ($fifteenMinsAgo) {
                $isOnline = $device->last_seen_at && Carbon::parse($device->last_seen_at)->greaterThanOrEqualTo($fifteenMinsAgo);
                $device->is_online = $isOnline;
                $device->last_seen_human = $device->last_seen_at ? Carbon::parse($device->last_seen_at)->diffForHumans() : 'Never';
                $device->last_login_human = $device->last_login_at ? Carbon::parse($device->last_login_at)->diffForHumans() : 'Never';
                $device->has_token = !empty($device->api_token);
                $device->has_fcm = !empty($device->fcm_token);
                $device->total_messages = (int)($device->total_messages ?? 0);
                $device->sent_messages = (int)($device->sent_messages ?? 0);
                $device->failed_messages = (int)($device->failed_messages ?? 0);
                return $device;
            });

            $data = $devices->toArray();
            $data['stats'] = [
                'total' => (int)($stats->total ?? 0),
                'active' => (int)($stats->active ?? 0),
                'inactive' => (int)($stats->inactive ?? 0),
                'online' => (int)($stats->online ?? 0),
                'active_24h' => (int)($stats->active_24h ?? 0),
                'android' => (int)($stats->android ?? 0),
                'ios' => (int)($stats->ios ?? 0),
                'virtual' => (int)($stats->is_virtual_count ?? 0),
            ];

            return returnData(2000, $data);
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Failed to load user devices.');
        }
    }

    /**
     * Store a new device.
     */
    public function store(Request $request)
    {
        try {
            $input = $request->all();
            $validator = $this->model->validate($input);
            if ($validator->fails()) {
                return returnData(3000, $validator->errors());
            }

            $device = new UserDevice();
            $device->fill($input);
            $device->status = $request->input('status', 1);
            $device->save();

            return returnData(2000, $device, 'User device registered successfully.');
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Failed to register device.');
        }
    }

    /**
     * Display device detailed dashboard information & telemetry histories based on message table device_id.
     */
    public function show($id)
    {
        try {
            $device = UserDevice::with('user')->find($id);
            if (!$device) {
                return returnData(404, null, 'Device not found.');
            }

            $fifteenMinsAgo = Carbon::now()->subMinutes(15);
            $device->is_online = $device->last_seen_at && Carbon::parse($device->last_seen_at)->greaterThanOrEqualTo($fifteenMinsAgo);
            $device->last_seen_formatted = $device->last_seen_at ? Carbon::parse($device->last_seen_at)->format('d M Y, h:i:s A') : 'N/A';
            $device->last_login_formatted = $device->last_login_at ? Carbon::parse($device->last_login_at)->format('d M Y, h:i:s A') : 'N/A';
            $device->last_logout_formatted = $device->last_logout_at ? Carbon::parse($device->last_logout_at)->format('d M Y, h:i:s A') : 'N/A';
            $device->created_formatted = $device->created_at ? Carbon::parse($device->created_at)->format('d M Y, h:i:s A') : 'N/A';
            $device->last_seen_human = $device->last_seen_at ? Carbon::parse($device->last_seen_at)->diffForHumans() : 'Never';
            $device->last_login_human = $device->last_login_at ? Carbon::parse($device->last_login_at)->diffForHumans() : 'Never';
            $device->has_token = !empty($device->api_token);
            $device->has_fcm = !empty($device->fcm_token);

            $userId = $device->user_id;
            $user = $device->user;

            // 1. User Balance & Billing info
            $paymentsAndSpent = $user ? showBalance($user->id) : (object)['balance' => 0, 'total_recharge' => 0, 'total_spent' => 0];
            $balanceData = [
                'current_balance' => $paymentsAndSpent->balance ?? 0,
                'total_recharge'  => $paymentsAndSpent->total_recharge ?? 0,
                'total_spent'     => number_format(($paymentsAndSpent->total_recharge ?? 0) - ($paymentsAndSpent->balance ?? 0), 2),
            ];

            // 2. SMS Stats strictly based on device_id from sms_messages table
            $smsQuery = \App\Models\SmsMessage::where('device_id', $device->id);
            $smsStats = (clone $smsQuery)->selectRaw("
                COUNT(id) as total,
                COUNT(CASE WHEN status = 'sent' THEN 1 END) as sent,
                COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed,
                COUNT(CASE WHEN status IN ('pending', 'processing') THEN 1 END) as pending
            ")->first();

            $totalSms   = (int)($smsStats->total ?? 0);
            $successSms = (int)($smsStats->sent ?? 0);
            $failedSms  = (int)($smsStats->failed ?? 0);
            $pendingSms = (int)($smsStats->pending ?? 0);
            $processed  = $successSms + $failedSms;
            $successRate = $processed > 0 ? round(($successSms / $processed) * 100, 1) : 0;

            // 3. Recent 20 SMS messages for this specific device_id
            $recentMessages = (clone $smsQuery)
                ->orderBy('id', 'desc')
                ->take(20)
                ->get()
                ->map(function ($m) {
                    return [
                        'id' => $m->id,
                        'device_id' => $m->device_id,
                        'recipient' => $m->recipient,
                        'message' => mb_strlen($m->message) > 65 ? mb_substr($m->message, 0, 62) . '...' : $m->message,
                        'full_message' => $m->message,
                        'status' => $m->status,
                        'attempts' => (int)$m->attempts,
                        'last_error' => $m->last_error,
                        'sent_at' => $m->sent_at ? Carbon::parse($m->sent_at)->format('d M, h:i A') : null,
                        'failed_at' => $m->failed_at ? Carbon::parse($m->failed_at)->format('d M, h:i A') : null,
                        'created_at' => $m->created_at ? Carbon::parse($m->created_at)->format('d M Y, h:i A') : 'N/A',
                    ];
                });

            // 4. Gateway Dispatch Channels (sms_counts table)
            $smsCountsList = \App\Models\SmsCount::where('user_id', $userId)
                ->orderBy('month', 'desc')
                ->orderBy('type', 'asc')
                ->take(10)
                ->get()
                ->map(function ($c) {
                    return [
                        'id' => $c->id,
                        'month' => $c->month,
                        'operator_name' => $c->operator_name ?: ($c->type == 2 ? 'API Gateway' : 'Device SIM'),
                        'operator_number' => $c->operator_number ?: 'N/A',
                        'sim_slot' => $c->sim_slot,
                        'type' => $c->type,
                        'type_label' => $c->type == 2 ? 'API Gateway' : 'Phone SIM',
                        'total_request' => (int)$c->total_request,
                        'total_sent' => (int)$c->total_sent,
                        'total_failed' => (int)$c->total_failed,
                        'last_update' => $c->last_update ? Carbon::parse($c->last_update)->format('d M Y, h:i A') : 'N/A',
                    ];
                });

            // 5. 12-Month Traffic Trends strictly based on device_id
            $startDate12 = Carbon::now()->subMonths(11)->startOfMonth()->toDateTimeString();
            $monthWiseMessages = DB::table('sms_messages')
                ->selectRaw("
                    DATE_FORMAT(created_at, '%Y-%m') as month_key,
                    COUNT(id) as total,
                    COUNT(CASE WHEN status = 'sent' THEN 1 END) as sent,
                    COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed
                ")
                ->where('device_id', $device->id)
                ->where('created_at', '>=', $startDate12)
                ->groupBy('month_key')
                ->get()
                ->keyBy('month_key');

            $months = [];
            $sentSeries = [];
            $failedSeries = [];

            for ($i = 11; $i >= 0; $i--) {
                $mKey = Carbon::now()->subMonths($i)->format('Y-m');
                $mLabel = Carbon::now()->subMonths($i)->format('M Y');
                $mStats = $monthWiseMessages->get($mKey);

                $months[] = $mLabel;
                $sentSeries[] = $mStats ? (int)$mStats->sent : 0;
                $failedSeries[] = $mStats ? (int)$mStats->failed : 0;
            }

            // Charts Config
            $charts = [
                'smsRequestStatus' => [
                    'series' => [$successSms, $failedSms, $pendingSms],
                    'chartOptions' => [
                        'chart' => ['type' => 'donut', 'foreColor' => '#64748b'],
                        'colors' => ['#10B981', '#EF4444', '#F59E0B'],
                        'labels' => [
                            "Delivered ({$successSms})",
                            "Failed ({$failedSms})",
                            "In Queue ({$pendingSms})"
                        ],
                        'legend' => ['position' => 'bottom'],
                        'dataLabels' => ['enabled' => true],
                        'stroke' => ['width' => 2, 'colors' => ['#ffffff']],
                    ],
                ],
                'monthlySmsRequestStatus' => [
                    'series' => [
                        ['name' => 'Delivered SMS', 'data' => $sentSeries],
                        ['name' => 'Failed SMS', 'data' => $failedSeries],
                    ],
                    'chartOptions' => [
                        'chart' => ['type' => 'bar', 'stacked' => true, 'foreColor' => '#64748b', 'toolbar' => ['show' => false]],
                        'colors' => ['#10B981', '#EF4444'],
                        'plotOptions' => ['bar' => ['horizontal' => false, 'columnWidth' => '45%', 'borderRadius' => 4]],
                        'dataLabels' => ['enabled' => false],
                        'xaxis' => ['categories' => $months],
                        'legend' => ['position' => 'top', 'horizontalAlign' => 'right'],
                        'tooltip' => ['theme' => 'dark'],
                    ],
                ],
            ];

            $result = [
                'device'          => $device,
                'user'            => $user,
                'balance'         => $balanceData,
                'sms_stats'       => [
                    'total_sms'    => $totalSms,
                    'success_sms'  => $successSms,
                    'failed_sms'   => $failedSms,
                    'pending_sms'  => $pendingSms,
                    'success_rate' => $successRate,
                ],
                'recent_messages' => $recentMessages,
                'sms_counts_list' => $smsCountsList,
                'charts'          => $charts,
            ];

            return returnData(2000, $result);
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Error fetching device details.');
        }
    }

    /**
     * Update device information.
     */
    public function update(Request $request, $id)
    {
        try {
            $device = UserDevice::find($id ?: $request->input('id'));
            if (!$device) {
                return returnData(404, null, 'Device not found.');
            }

            $input = $request->all();
            $validator = $this->model->validate($input);
            if ($validator->fails()) {
                return returnData(3000, $validator->errors());
            }

            $device->fill($input);
            $device->save();

            return returnData(2000, $device, 'Device updated successfully.');
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Failed to update device.');
        }
    }

    /**
     * Toggle Active / Inactive Status.
     */
    public function status()
    {
        try {
            $id = request()->input('id');
            $device = UserDevice::find($id);

            if (!$device) {
                return returnData(404, null, 'Device not found.');
            }

            $newStatus = ($device->status == 1) ? 0 : 1;
            $device->status = $newStatus;
            $device->save();

            $msg = ($newStatus == 1) ? 'Device activated successfully.' : 'Device deactivated successfully.';
            $type = ($newStatus == 1) ? 'success' : 'warning';

            return returnData(2000, $type, $msg);
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Failed to change device status.');
        }
    }

    /**
     * Force logout device / revoke active session token.
     */
    public function forceLogout($id)
    {
        try {
            $device = UserDevice::find($id);
            if (!$device) {
                return returnData(404, null, 'Device not found.');
            }

            $device->forceFill([
                'api_token' => null,
                'last_logout_at' => Carbon::now(),
            ])->save();

            return returnData(2000, null, 'Device session token revoked and logged out.');
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Failed to logout device.');
        }
    }

    /**
     * Bulk actions on multiple devices.
     */
    public function bulkAction(Request $request)
    {
        try {
            $action = $request->input('action');
            $ids    = $request->input('ids', []);

            if (empty($ids) || !is_array($ids)) {
                return returnData(400, null, 'No devices selected.');
            }

            switch ($action) {
                case 'activate':
                    UserDevice::whereIn('id', $ids)->update(['status' => 1]);
                    return returnData(2000, null, 'Selected devices activated.');

                case 'deactivate':
                    UserDevice::whereIn('id', $ids)->update(['status' => 0]);
                    return returnData(2000, null, 'Selected devices deactivated.');

                case 'force_logout':
                    UserDevice::whereIn('id', $ids)->update([
                        'api_token' => null,
                        'last_logout_at' => Carbon::now(),
                    ]);
                    return returnData(2000, null, 'Session tokens revoked for selected devices.');

                case 'delete':
                    UserDevice::whereIn('id', $ids)->delete();
                    return returnData(2000, null, 'Selected devices deleted.');

                default:
                    return returnData(400, null, 'Invalid bulk action specified.');
            }
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Bulk operation failed.');
        }
    }

    /**
     * Remove the specified device.
     */
    public function destroy($id)
    {
        try {
            $device = UserDevice::find($id);
            if (!$device) {
                return returnData(404, null, 'Device not found.');
            }

            $device->delete();
            return returnData(2000, null, 'Device deleted successfully.');
        } catch (\Exception $exception) {
            return returnData(5000, $exception->getMessage(), 'Failed to delete device.');
        }
    }
}
