<?php

namespace App\Services;

use App\Models\SmsLog;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Exception;

class SmsService
{
    protected $baseUrl;
    protected $token;
    protected $senderId;

    public function __construct()
    {
        $this->baseUrl = config('sms.base_url', 'https://app.smartsmssolutions.com/io/api/client/v1');
        $this->token = config('sms.token');
        $this->senderId = config('sms.sender_id', 'SlarryLaundry');
    }

    /**
     * Send SMS to a single recipient
.     */
    public function sendSms(string $phoneNumber, string $message, array $options = []): array
    {
        // Prepare a ref_id early so it is always available for logging
        $refId = $options['ref_id'] ?? $this->generateRefId();

        try {
            // Clean and format phone number
            $phoneNumber = $this->formatPhoneNumber($phoneNumber);
            
            // Prepare the request payload for Smart SMS Solutions API
            // Sanitize and enforce Sender ID rules (max 11 chars, alphanumeric)
            $rawSender = $options['sender_id'] ?? $this->senderId;
            $sanitizedSender = preg_replace('/[^A-Za-z0-9]/', '', (string) $rawSender);
            $enforcedSender = substr($sanitizedSender ?: 'SENDERID', 0, 11);

            // Smart SMS Solutions API expects specific parameter names
            $payload = [
                'token' => $this->token,
                'sender' => $enforcedSender,
                'to' => $phoneNumber,
                'message' => $message,
                // Ensure these are integers as per API docs
                'type' => isset($options['type']) ? (string) ((int) $options['type']) : '0', // 0 for plain text, 1 for flash SMS
                'routing' => isset($options['routing']) ? (string) ((int) $options['routing']) : '4', // 4 for corporate route
                'ref_id' => $refId,
            ];

            // Use cURL for proper form data submission
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $this->baseUrl . '/sms/',
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => http_build_query($payload),
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 30,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_HTTPHEADER => [
                    'Content-Type: application/x-www-form-urlencoded',
                    'Accept: application/json',
                ],
            ]);

            $responseBody = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $curlError = curl_error($ch);
            curl_close($ch);

            if ($curlError) {
                throw new Exception("cURL Error: " . $curlError);
            }

            // Parse response
            $responseData = json_decode($responseBody, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                $responseData = ['raw_response' => $responseBody];
            }

            // Treat as success only when HTTP is 2xx and provider code is 1000
            $providerCode = is_array($responseData) && array_key_exists('code', $responseData) ? (string) $responseData['code'] : null;
            $isSuccessful = ($httpCode >= 200 && $httpCode < 300) && ($providerCode === '1000');

            // Diagnostic logging of request/response (exclude token)
            Log::info('SmartSMS API response', [
                'endpoint' => $this->baseUrl . '/sms/',
                'http_code' => $httpCode,
                'request' => [
                    'sender' => $enforcedSender,
                    'to' => $phoneNumber,
                    'type' => $payload['type'],
                    'routing' => $payload['routing'],
                    'ref_id' => $refId,
                ],
                'response' => $responseData,
            ]);

            // Always log the SMS attempt with proper timestamp
            $logPayload = [
                'phone_number' => $phoneNumber,
                'message' => $message,
                'status' => $isSuccessful ? 'sent' : 'failed',
                'response' => array_merge(['http_code' => $httpCode], (array) $responseData),
                'ref_id' => $refId,
                'sent_at' => now(),
            ];
            // Attach optional context
            foreach (['order_id', 'customer_id', 'template_id'] as $ctxKey) {
                if (array_key_exists($ctxKey, $options)) {
                    $logPayload[$ctxKey] = $options[$ctxKey];
                }
            }
            $this->logSms($logPayload);

            if ($isSuccessful) {
                return [
                    'success' => true,
                    'message' => 'SMS sent successfully',
                    'data' => $responseData,
                    'ref_id' => $refId,
                ];
            } else {
                return [
                    'success' => false,
                    'message' => ($responseData['message'] ?? 'Failed to send SMS') . ($providerCode ? " (code: {$providerCode})" : ''),
                    'error' => $responseData,
                ];
            }

        } catch (Exception $e) {
            Log::error('SMS Service Error: ' . $e->getMessage(), [
                'phone' => $phoneNumber,
                'message' => $message,
                'trace' => $e->getTraceAsString()
            ]);

            // Log failed attempt with proper timestamp
            $logPayload = [
                'phone_number' => $phoneNumber,
                'message' => $message,
                'status' => 'failed',
                'response' => ['error' => $e->getMessage()],
                'ref_id' => $refId,
                'sent_at' => now(),
            ];
            foreach (['order_id', 'customer_id', 'template_id'] as $ctxKey) {
                if (array_key_exists($ctxKey, $options)) {
                    $logPayload[$ctxKey] = $options[$ctxKey];
                }
            }
            $this->logSms($logPayload);

            return [
                'success' => false,
                'message' => 'SMS service error: ' . $e->getMessage(),
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * Send bulk SMS to multiple recipients
     */
    public function sendBulkSms(array $phoneNumbers, string $message, array $options = []): array
    {
        $results = [];
        $successCount = 0;
        $failureCount = 0;

        foreach ($phoneNumbers as $phoneNumber) {
            $result = $this->sendSms($phoneNumber, $message, $options);
            $results[] = [
                'phone' => $phoneNumber,
                'result' => $result,
            ];

            if ($result['success']) {
                $successCount++;
            } else {
                $failureCount++;
            }
        }

        return [
            'success' => $successCount > 0,
            'total' => count($phoneNumbers),
            'successful' => $successCount,
            'failed' => $failureCount,
            'results' => $results,
        ];
    }

    /**
     * Send order ready notification
     */
    public function sendOrderReadyNotification(string $phoneNumber, string $customerName, string $orderNumber, array $context = []): array
    {
        $message = "Hi {$customerName}, Order {$orderNumber} is READY! Pickup at More blessing complex, Ikare. Thanks, Slarry Laundry.";
        
        return $this->sendSms($phoneNumber, $message, array_merge([
            'type' => '0', // Regular SMS
            'ref_id' => 'ORDER_READY_' . $orderNumber . '_' . time(),
        ], $context));
    }

    /**
     * Send order status update notification
     */
    public function sendOrderStatusNotification(string $phoneNumber, string $customerName, string $orderNumber, string $status, array $context = []): array
    {
        $statusMessages = [
            'created' => "Hello {$customerName}, your laundry order {$orderNumber} has been received and is being processed. We'll notify you when it's ready! - Slarry Laundry Service",
            'processing' => "Hello {$customerName}, your laundry order {$orderNumber} is currently being processed. We'll notify you when it's ready for pickup. - Slarry Laundry Service",
            'ready' => "Hi {$customerName}, Order {$orderNumber} is READY! Pickup at More blessing complex, Ikare. Thanks, Slarry Laundry.",
            'completed' => "Hello {$customerName}, thank you for choosing Slarry Laundry Service! Your order {$orderNumber} has been completed. We look forward to serving you again. Contact: Ayodejiademide@gmail.com",
            'cancelled' => "Hello {$customerName}, your laundry order {$orderNumber} has been cancelled. If you have any questions, please contact us at Ayodejiademide@gmail.com - Slarry Laundry Service",
        ];

        $message = $statusMessages[$status] ?? "Hello {$customerName}, your order {$orderNumber} status has been updated to: " . ucfirst($status);

        return $this->sendSms($phoneNumber, $message, array_merge([
            'type' => '0',
            'ref_id' => 'ORDER_STATUS_' . $orderNumber . '_' . strtoupper($status) . '_' . time(),
        ], $context));
    }

    /**
     * Send order status update notification with outstanding balance
     */
    public function sendOrderStatusNotificationWithBalance(string $phoneNumber, string $customerName, string $orderNumber, string $status, float $outstandingBalance, array $context = []): array
    {
        if ($outstandingBalance > 0) {
            // Messages with outstanding balance
            $statusMessages = [
                'created' => "Hello {$customerName}, your laundry order {$orderNumber} has been received. Outstanding balance: N" . number_format($outstandingBalance, 2) . ". - Slarry Laundry Service",
                'processing' => "Hello {$customerName}, your laundry order {$orderNumber} is being processed. Outstanding balance: N" . number_format($outstandingBalance, 2) . ". - Slarry Laundry Service",
                'ready' => "Hi {$customerName}, Order {$orderNumber} is READY! Bal: N" . number_format($outstandingBalance, 2) . ". Pickup at More blessing complex, Ikare. Thanks, Slarry Laundry.",
                'completed' => "Hello {$customerName}, your laundry order {$orderNumber} has been completed. Outstanding balance: N" . number_format($outstandingBalance, 2) . ". Thank you for choosing Slarry Laundry Service!",
                'cancelled' => "Hello {$customerName}, your laundry order {$orderNumber} has been cancelled. Outstanding balance: N" . number_format($outstandingBalance, 2) . ". If you have any questions, please contact us at Ayodejiademide@gmail.com - Slarry Laundry Service",
            ];
        } else {
            // Messages without outstanding balance
            $statusMessages = [
                'created' => "Hello {$customerName}, your laundry order {$orderNumber} has been received and is being processed. - Slarry Laundry Service",
                'processing' => "Hello {$customerName}, your laundry order {$orderNumber} is currently being processed. We'll notify you when it's ready for pickup. - Slarry Laundry Service",
                'ready' => "Hi {$customerName}, Order {$orderNumber} is READY! Paid in full. Pickup at More blessing complex, Ikare. Thanks, Slarry Laundry.",
                'completed' => "Hello {$customerName}, your laundry order {$orderNumber} has been completed. Thank you for choosing Slarry Laundry Service!",
                'cancelled' => "Hello {$customerName}, your laundry order {$orderNumber} has been cancelled. If you have any questions, please contact us at Ayodejiademide@gmail.com - Slarry Laundry Service",
            ];
        }

        $message = $statusMessages[$status] ?? "Hello {$customerName}, your order {$orderNumber} status has been updated to: " . ucfirst($status) . ". Outstanding balance: N" . number_format($outstandingBalance, 2);

        return $this->sendSms($phoneNumber, $message, array_merge([
            'type' => '0',
            'ref_id' => 'ORDER_STATUS_' . $orderNumber . '_' . strtoupper($status) . '_BALANCE_' . time(),
        ], $context));
    }

    /**
     * Check SMS balance
     */
    public function checkBalance(): array
    {
        try {
            // Get current balance from cache or calculate from SMS logs
            $totalSent = \App\Models\SmsLog::where('status', 'sent')->count();
            $remainingBalance = max(0, 300 - $totalSent); // Start with 300, subtract sent SMS

            return [
                'success' => true,
                'balance' => $remainingBalance,
                'data' => [
                    'balance' => $remainingBalance,
                    'currency' => 'NGN',
                    'total_sent' => $totalSent,
                    'initial_balance' => 300
                ],
            ];

            // Uncomment below for actual API integration
            /*
            $payload = ['token' => $this->token];

            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $this->baseUrl . '/balance/',
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => http_build_query($payload),
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 30,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_HTTPHEADER => [
                    'Content-Type: application/x-www-form-urlencoded',
                    'Accept: application/json',
                ],
            ]);

            $responseBody = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $curlError = curl_error($ch);
            curl_close($ch);

            if ($curlError) {
                throw new Exception("cURL Error: " . $curlError);
            }

            $responseData = json_decode($responseBody, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                $responseData = ['raw_response' => $responseBody];
            }

            $isSuccessful = $httpCode >= 200 && $httpCode < 300;

            if ($isSuccessful) {
                return [
                    'success' => true,
                    'balance' => $responseData['balance'] ?? 0,
                    'data' => $responseData,
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to check balance',
                    'error' => $responseData,
                ];
            }
            */

        } catch (Exception $e) {
            Log::error('SMS Balance Check Error: ' . $e->getMessage());

            return [
                'success' => false,
                'message' => 'Failed to check SMS balance',
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * Format phone number to international format
     */
    public function formatPhoneNumber(string $phoneNumber): string
    {
        // Handle +234 format first (before removing non-numeric characters)
        if (substr($phoneNumber, 0, 4) === '+234') {
            $phoneNumber = substr($phoneNumber, 1); // Remove + to get 234xxxxxxxxxx
        }

        // Remove all non-numeric characters
        $phoneNumber = preg_replace('/[^0-9]/', '', $phoneNumber);

        // Handle Nigerian phone numbers
        if (strlen($phoneNumber) === 11 && substr($phoneNumber, 0, 1) === '0') {
            // Convert 07043167491 to 2347043167491
            $phoneNumber = '234' . substr($phoneNumber, 1);
        } elseif (strlen($phoneNumber) === 10) {
            // Convert 7043167491 to 2347043167491
            $phoneNumber = '234' . $phoneNumber;
        } elseif (strlen($phoneNumber) === 13 && substr($phoneNumber, 0, 3) === '234') {
            // Already in correct format (2347043167491)
            return $phoneNumber;
        } elseif (strlen($phoneNumber) > 13) {
            // Handle cases where there might be extra digits
            if (substr($phoneNumber, 0, 3) === '234') {
                $phoneNumber = substr($phoneNumber, 0, 13); // Take first 13 digits
            }
        }

        return $phoneNumber;
    }

    /**
     * Generate unique reference ID
     */
    protected function generateRefId(): string
    {
        return 'LAUNDRY_' . time() . '_' . rand(1000, 9999);
    }

    /**
     * Log SMS attempt to file (no database)
     */
    protected function logSms(array $data): void
    {
        try {
            $context = [
                'order_id' => $data['order_id'] ?? null,
                'customer_id' => $data['customer_id'] ?? null,
                'template_id' => $data['template_id'] ?? null,
                'phone_number' => $data['phone_number'] ?? null,
                'ref_id' => $data['ref_id'] ?? null,
                'sent_at' => ($data['sent_at'] ?? now())->toDateTimeString(),
                'response' => $data['response'] ?? null,
            ];

            if (($data['status'] ?? 'failed') === 'sent') {
                Log::info('SMS Logged (sent)', array_merge(['message' => $data['message'] ?? null], $context));
            } else {
                Log::warning('SMS Logged (failed)', array_merge(['message' => $data['message'] ?? null], $context));
            }
        } catch (Exception $e) {
            Log::error('Failed to write SMS log to file: ' . $e->getMessage());
        }
    }

    /**
     * Get SMS delivery status
     */
    public function getDeliveryStatus(string $refId): array
    {
        try {
            $response = Http::timeout(30)
                ->asForm()
                ->post($this->baseUrl . '/status', [
                    'token' => $this->token,
                    'ref_id' => $refId,
                ]);

            $responseData = $response->json();

            if ($response->successful()) {
                return [
                    'success' => true,
                    'status' => $responseData['status'] ?? 'unknown',
                    'data' => $responseData,
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to get delivery status',
                    'error' => $responseData,
                ];
            }

        } catch (Exception $e) {
            Log::error('SMS Status Check Error: ' . $e->getMessage());

            return [
                'success' => false,
                'message' => 'Failed to check SMS status',
                'error' => $e->getMessage(),
            ];
        }
    }
}
