<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Pricing;
use App\Models\SmsMessage;
use App\Models\User;
use App\Services\FcmService;
use App\Services\PackageActivationService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class GatewayApiController extends Controller
{
    /**
     * 1. Verify API Token and return User & Active Package details.
     */
    public function verifyToken(Request $request): JsonResponse
    {
        $user = $request->user();
        $activePackage = PackageActivationService::getUserActivePackage($user);

        return response()->json([
            'status' => 2000,
            'success' => true,
            'message' => 'API Token is valid.',
            'data' => [
                'user' => [
                    'id' => $user->id,
                    'name' => $user->name,
                    'company_name' => $user->company_name,
                    'email' => $user->email,
                    'contact_number' => $user->contact_number ?? $user->phone,
                    'masking_rate' => $user->masking_rate,
                    'non_masking_rate' => $user->non_masking_rate,
                    'status' => $user->status === 1 ? 'active' : 'inactive',
                ],
                'active_package' => $activePackage ? [
                    'package_name' => $activePackage->package_name,
                    'billing_type' => $activePackage->billing_type,
                    'total_sms' => $activePackage->total_sms,
                    'used_sms' => $activePackage->used_sms,
                    'remaining_sms' => $activePackage->remaining_sms,
                    'daily_limit' => $activePackage->daily_limit,
                    'daily_sent' => $activePackage->daily_sent,
                    'start_date' => $activePackage->start_date ? $activePackage->start_date->toIso8601String() : null,
                    'expire_date' => $activePackage->expire_date ? $activePackage->expire_date->toIso8601String() : null,
                    'days_remaining' => $activePackage->days_remaining,
                    'is_expired' => $activePackage->is_expired,
                ] : null,
            ],
        ]);
    }

    /**
     * 2. Send Single SMS.
     * Inserts into sms_messages base table, checks package quota, and notifies gateway node.
     */
    public function sendSingle(Request $request): JsonResponse
    {
        $user = $request->user();

        $validated = $request->validate([
            'recipient' => 'required|string|max:30',
            'message' => 'required|string|max:1000',
            'sms_type' => 'nullable|string|in:masking,non_masking,T,P',
            'device_id' => 'nullable',
            'schedule_at' => 'nullable|date',
        ]);

        $recipientRaw = $validated['recipient'];
        $cleanPhone = preg_replace('/[^\d+]/', '', trim($recipientRaw));

        if (empty($cleanPhone) || strlen($cleanPhone) < 6) {
            return response()->json([
                'status' => 4022,
                'success' => false,
                'message' => 'Invalid recipient phone number format. Must be at least 6 digits.',
            ], 422);
        }

        $messageText = trim($validated['message']);
        $isMasking = in_array(strtolower($validated['sms_type'] ?? ''), ['masking', 't'], true);
        $smsTypeStr = $isMasking ? 'masking' : 'non_masking';

        // Calculate message parts
        $charLength = mb_strlen($messageText);
        $isUnicode = preg_match('/[^\x00-\x7F]/', $messageText);
        $partLimit = $isUnicode ? 70 : 160;
        $parts = (int) max(1, ceil($charLength / $partLimit));

        // Validate package eligibility
        $check = PackageActivationService::canUserSendSms($user, $parts, $isMasking);
        if (!$check['allowed']) {
            return response()->json([
                'status' => 4003,
                'success' => false,
                'message' => $check['reason'],
                'remaining_sms' => $check['remaining_sms'],
            ], 403);
        }

        $targetDeviceId = $request->input('device_id');
        if ($targetDeviceId) {
            $deviceModel = \App\Models\UserDevice::where('user_id', $user->id)
                ->where(function ($q) use ($targetDeviceId) {
                    $q->where('id', $targetDeviceId)->orWhere('device_id', $targetDeviceId);
                })->first();
            $targetDeviceId = $deviceModel ? $deviceModel->id : (is_numeric($targetDeviceId) ? (int) $targetDeviceId : null);
        }

        // Insert into sms_messages base table
        $smsMessage = SmsMessage::create([
            'user_id' => $user->id,
            'device_id' => $targetDeviceId,
            'recipient' => $cleanPhone,
            'message' => $messageText,
            'sms_type' => $smsTypeStr,
            'sms_parts' => $parts,
            'batch_id' => null,
            'schedule_at' => $request->filled('schedule_at') ? Carbon::parse($request->input('schedule_at')) : null,
            'status' => SmsMessage::STATUS_PENDING,
            'attempts' => 0,
        ]);

        // Deduct SMS usage
        PackageActivationService::deductSmsUsage($user, $parts);

        // Dispatch FCM Push Notification to Android node
        FcmService::sendNewSmsNotification(
            $user->id,
            $smsMessage->recipient,
            $smsMessage->message,
            $smsMessage->id,
            $targetDeviceId
        );

        $activePackage = PackageActivationService::getUserActivePackage($user);

        return response()->json([
            'status' => 2000,
            'success' => true,
            'message' => 'SMS submitted to gateway queue successfully.',
            'data' => [
                'id' => $smsMessage->id,
                'recipient' => $smsMessage->recipient,
                'message' => $smsMessage->message,
                'sms_type' => $smsMessage->sms_type,
                'sms_parts' => $smsMessage->sms_parts,
                'status' => $smsMessage->status,
                'created_at' => $smsMessage->created_at->toIso8601String(),
            ],
            'quota' => [
                'remaining_sms' => $activePackage ? $activePackage->remaining_sms : -1,
                'daily_sent' => $activePackage ? $activePackage->daily_sent : 0,
                'daily_limit' => $activePackage ? $activePackage->daily_limit : 0,
            ],
        ]);
    }

    /**
     * 3. Send Bulk SMS.
     * Inserts batch into sms_messages base table and notifies gateway.
     */
    public function sendBulk(Request $request): JsonResponse
    {
        $user = $request->user();

        $validated = $request->validate([
            'recipients' => 'required',
            'message' => 'required|string|max:1000',
            'sms_type' => 'nullable|string|in:masking,non_masking,T,P',
            'device_id' => 'nullable',
            'schedule_at' => 'nullable|date',
        ]);

        $rawRecipients = $validated['recipients'];
        if (is_string($rawRecipients)) {
            $rawList = preg_split('/[\r\n,]+/', $rawRecipients);
        } elseif (is_array($rawRecipients)) {
            $rawList = $rawRecipients;
        } else {
            $rawList = [];
        }

        $validRecipients = [];
        foreach ($rawList as $r) {
            $clean = preg_replace('/[^\d+]/', '', trim((string) $r));
            if (!empty($clean) && strlen($clean) >= 6 && strlen($clean) <= 15) {
                $validRecipients[] = $clean;
            }
        }

        if (empty($validRecipients)) {
            return response()->json([
                'status' => 4022,
                'success' => false,
                'message' => 'No valid phone numbers provided in recipient list.',
            ], 422);
        }

        $messageText = trim($validated['message']);
        $isMasking = in_array(strtolower($validated['sms_type'] ?? ''), ['masking', 't'], true);
        $smsTypeStr = $isMasking ? 'masking' : 'non_masking';

        $charLength = mb_strlen($messageText);
        $isUnicode = preg_match('/[^\x00-\x7F]/', $messageText);
        $partLimit = $isUnicode ? 70 : 160;
        $parts = (int) max(1, ceil($charLength / $partLimit));
        $totalRequiredCredits = count($validRecipients) * $parts;

        // Validate package eligibility
        $check = PackageActivationService::canUserSendSms($user, $totalRequiredCredits, $isMasking);
        if (!$check['allowed']) {
            return response()->json([
                'status' => 4003,
                'success' => false,
                'message' => $check['reason'],
                'required_credits' => $totalRequiredCredits,
                'remaining_sms' => $check['remaining_sms'],
            ], 403);
        }

        $targetDeviceId = $request->input('device_id');
        if ($targetDeviceId) {
            $deviceModel = \App\Models\UserDevice::where('user_id', $user->id)
                ->where(function ($q) use ($targetDeviceId) {
                    $q->where('id', $targetDeviceId)->orWhere('device_id', $targetDeviceId);
                })->first();
            $targetDeviceId = $deviceModel ? $deviceModel->id : (is_numeric($targetDeviceId) ? (int) $targetDeviceId : null);
        }

        $batchId = 'BATCH_' . strtoupper(Str::random(10)) . '_' . time();
        $now = Carbon::now();
        $scheduleAt = $request->filled('schedule_at') ? Carbon::parse($request->input('schedule_at')) : null;

        $insertData = [];
        foreach ($validRecipients as $phone) {
            $insertData[] = [
                'user_id' => $user->id,
                'device_id' => $targetDeviceId,
                'recipient' => $phone,
                'message' => $messageText,
                'sms_type' => $smsTypeStr,
                'sms_parts' => $parts,
                'batch_id' => $batchId,
                'schedule_at' => $scheduleAt,
                'status' => SmsMessage::STATUS_PENDING,
                'attempts' => 0,
                'created_at' => $now,
                'updated_at' => $now,
            ];
        }

        foreach (array_chunk($insertData, 500) as $chunk) {
            SmsMessage::insert($chunk);
        }

        // Deduct usage
        PackageActivationService::deductSmsUsage($user, $totalRequiredCredits);

        // Notify Android gateway
        FcmService::sendLargeMessageNotification(
            $user->id,
            count($validRecipients),
            'Bulk SMS Batch',
            $messageText,
            $targetDeviceId
        );

        $activePackage = PackageActivationService::getUserActivePackage($user);

        return response()->json([
            'status' => 2000,
            'success' => true,
            'message' => "Successfully queued " . count($validRecipients) . " messages in batch {$batchId}.",
            'data' => [
                'batch_id' => $batchId,
                'total_recipients' => count($validRecipients),
                'sms_parts' => $parts,
                'total_sms_cost' => $totalRequiredCredits,
                'status' => 'pending',
                'created_at' => $now->toIso8601String(),
            ],
            'quota' => [
                'remaining_sms' => $activePackage ? $activePackage->remaining_sms : -1,
                'daily_sent' => $activePackage ? $activePackage->daily_sent : 0,
                'daily_limit' => $activePackage ? $activePackage->daily_limit : 0,
            ],
        ]);
    }

    /**
     * 4. Check SMS Delivery Status by Message ID from sms_messages base table.
     */
    public function checkStatus(Request $request, $id = null): JsonResponse
    {
        $targetId = $id ?: $request->input('id', $request->input('message_id'));

        if (!$targetId) {
            return response()->json([
                'status' => 4022,
                'success' => false,
                'message' => 'Message ID is required.',
            ], 422);
        }

        $userId = $request->user()->id;
        $message = SmsMessage::where('id', $targetId)
            ->where('user_id', $userId)
            ->first();

        if (!$message) {
            return response()->json([
                'status' => 4004,
                'success' => false,
                'message' => 'SMS Message not found.',
            ], 404);
        }

        return response()->json([
            'status' => 2000,
            'success' => true,
            'data' => [
                'id' => $message->id,
                'recipient' => $message->recipient,
                'message' => $message->message,
                'sms_type' => $message->sms_type,
                'sms_parts' => $message->sms_parts,
                'status' => $message->status,
                'attempts' => $message->attempts,
                'claimed_at' => $message->claimed_at ? $message->claimed_at->toIso8601String() : null,
                'sent_at' => $message->sent_at ? $message->sent_at->toIso8601String() : null,
                'failed_at' => $message->failed_at ? $message->failed_at->toIso8601String() : null,
                'last_error' => $message->last_error,
                'created_at' => $message->created_at->toIso8601String(),
            ],
        ]);
    }

    /**
     * 5. Check User Balance & Active Package Information.
     */
    public function checkBalance(Request $request): JsonResponse
    {
        $user = $request->user();
        $activePackage = PackageActivationService::getUserActivePackage($user);

        return response()->json([
            'status' => 2000,
            'success' => true,
            'data' => [
                'user' => [
                    'id' => $user->id,
                    'name' => $user->name,
                    'masking_rate' => $user->masking_rate,
                    'non_masking_rate' => $user->non_masking_rate,
                ],
                'has_active_package' => $activePackage !== null,
                'package' => $activePackage ? [
                    'package_name' => $activePackage->package_name,
                    'billing_type' => $activePackage->billing_type,
                    'total_sms' => $activePackage->total_sms,
                    'used_sms' => $activePackage->used_sms,
                    'remaining_sms' => $activePackage->remaining_sms,
                    'daily_limit' => $activePackage->daily_limit,
                    'daily_sent' => $activePackage->daily_sent,
                    'start_date' => $activePackage->start_date ? $activePackage->start_date->toIso8601String() : null,
                    'expire_date' => $activePackage->expire_date ? $activePackage->expire_date->toIso8601String() : null,
                    'days_remaining' => $activePackage->days_remaining,
                    'is_expired' => $activePackage->is_expired,
                ] : null,
            ],
        ]);
    }

    /**
     * 6. SMS Delivery History & Logs from sms_messages base table.
     */
    public function getHistory(Request $request): JsonResponse
    {
        $userId = $request->user()->id;
        $status = $request->input('status');
        $recipient = $request->input('recipient', $request->input('phone'));
        $batchId = $request->input('batch_id');
        $startDate = $request->input('start_date', $request->input('date_from'));
        $endDate = $request->input('end_date', $request->input('date_to'));

        $query = SmsMessage::where('user_id', $userId)
            ->when($status, fn ($q) => $q->where('status', $status))
            ->when($recipient, fn ($q) => $q->where('recipient', 'LIKE', "%{$recipient}%"))
            ->when($batchId, fn ($q) => $q->where('batch_id', $batchId))
            ->when($startDate, fn ($q) => $q->where('created_at', '>=', $startDate))
            ->when($endDate, fn ($q) => $q->where('created_at', '<=', $endDate))
            ->orderBy('id', 'desc');

        $data = $query->paginate($request->input('perPage', 20));

        return response()->json([
            'status' => 2000,
            'success' => true,
            'data' => $data,
        ]);
    }

    /**
     * 7. Cancel a pending SMS message in the queue.
     */
    public function cancel(Request $request, $id): JsonResponse
    {
        $userId = $request->user()->id;
        $sms = SmsMessage::where('id', $id)->where('user_id', $userId)->first();

        if (!$sms) {
            return response()->json(['status' => 4004, 'message' => 'SMS not found.'], 404);
        }

        if ($sms->status !== SmsMessage::STATUS_PENDING) {
            return response()->json(['status' => 4000, 'message' => 'Only pending SMS messages can be cancelled.'], 422);
        }

        $sms->delete();

        return response()->json([
            'status' => 2000,
            'success' => true,
            'message' => 'SMS message cancelled and removed from queue.',
        ]);
    }
}
