<?php

namespace App\Services;

use App\Models\SmsConfiguration;
use Illuminate\Support\Facades\Log;

/**
 * SMSService
 * 
 * Public service for other modules to send SMS messages.
 * This is the main entry point for SMS functionality across the application.
 * 
 * Key Features:
 * - Simple, consistent API for sending SMS
 * - Standardized response format
 * - Automatic logging and error handling
 * - Support for both single and bulk SMS
 * 
 * Usage Example:
 * ```php
 * $smsService = app(SMSService::class);
 * 
 * $result = $smsService->send('+254712345678', 'Hello from SSHIA!');
 * 
 * if ($result['success']) {
 *     echo "SMS sent! Message ID: " . $result['message_id'];
 * } else {
 *     echo "Failed: " . $result['message'];
 * }
 * ```
 * 
 * @package App\Services
 */
class SMSService
{
    /**
     * SMS Provider instance.
     *
     * @var SMSProvider
     */
    protected SMSProvider $provider;

    /**
     * Configuration service instance.
     *
     * @var SmsConfigurationService
     */
    protected SmsConfigurationService $configService;

    /**
     * Create a new SMSService instance.
     *
     * @param SMSProvider $provider
     * @param SmsConfigurationService $configService
     */
    public function __construct(SMSProvider $provider, SmsConfigurationService $configService)
    {
        $this->provider = $provider;
        $this->configService = $configService;
    }

    /**
     * Send an SMS message to a single recipient.
     *
     * This is the main method for sending SMS messages throughout the application.
     * It provides a consistent interface and response format.
     *
     * @param string $phoneNumber Recipient phone number (any format)
     * @param string $message Message content to send
     * @return array Standardized response:
     *               - success (bool): Whether the SMS was sent successfully
     *               - message (string): Human-readable status message
     *               - message_id (string|null): Africa's Talking message ID if successful
     *               - log_id (int|null): Local log entry ID for tracking
     *               - cost (float|null): Cost of the SMS if available
     *               - error_code (string|null): Error code if failed
     * 
     * @example
     * ```php
     * // Basic usage
     * $result = $smsService->send('+254712345678', 'Hello!');
     * 
     * // With formatted phone number
     * $result = $smsService->send('0712345678', 'Hello!'); // Auto-formatted to +254712345678
     * 
     * // Check result
     * if ($result['success']) {
     *     // SMS was sent successfully
     *     Log::info("SMS sent with ID: " . $result['message_id']);
     * } else {
     *     // SMS failed
     *     Log::error("SMS failed: " . $result['message']);
     * }
     * ```
     */
    public function send(string $phoneNumber, string $message): array
    {
        // Validate message length
        if (empty($message)) {
            return [
                'success' => false,
                'message' => 'Message cannot be empty',
                'message_id' => null,
                'log_id' => null,
                'cost' => null,
                'error_code' => 'EMPTY_MESSAGE',
            ];
        }

        // Check if SMS is configured
        if (!$this->configService->isConfigured()) {
            return [
                'success' => false,
                'message' => 'SMS is not configured. Please contact the administrator.',
                'message_id' => null,
                'log_id' => null,
                'cost' => null,
                'error_code' => 'NOT_CONFIGURED',
            ];
        }

        // Log the send attempt
        Log::info('SMS send requested', [
            'phone' => $phoneNumber,
            'message_length' => strlen($message),
        ]);

        // Send via provider
        return $this->provider->sendSMS($phoneNumber, $message);
    }

    /**
     * Send SMS to multiple recipients.
     *
     * @param array $phoneNumbers Array of phone numbers
     * @param string $message Message content
     * @return array Results grouped by status:
     *               - total (int): Total recipients
     *               - sent (int): Successfully sent count
     *               - failed (int): Failed count
     *               - results (array): Individual results for each recipient
     */
    public function sendBulk(array $phoneNumbers, string $message): array
    {
        $results = [
            'total' => count($phoneNumbers),
            'sent' => 0,
            'failed' => 0,
            'results' => [],
        ];

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

            if ($result['success']) {
                $results['sent']++;
            } else {
                $results['failed']++;
            }
        }

        Log::info('Bulk SMS completed', [
            'total' => $results['total'],
            'sent' => $results['sent'],
            'failed' => $results['failed'],
        ]);

        return $results;
    }

    /**
     * Send a templated SMS message.
     * 
     * Replaces placeholders in the template with provided values.
     *
     * @param string $phoneNumber Recipient phone number
     * @param string $template Template string with {placeholder} syntax
     * @param array $variables Key-value pairs to replace in template
     * @return array Standard response
     * 
     * @example
     * ```php
     * $result = $smsService->sendTemplate(
     *     '+254712345678',
     *     'Hello {name}, your code is {code}',
     *     ['name' => 'John', 'code' => '123456']
     * );
     * // Sends: "Hello John, your code is 123456"
     * ```
     */
    public function sendTemplate(string $phoneNumber, string $template, array $variables): array
    {
        $message = $template;

        foreach ($variables as $key => $value) {
            // Cast null to empty string to avoid the literal "null" appearing in messages
            $message = str_replace('{' . $key . '}', $value ?? '', $message);
        }

        return $this->send($phoneNumber, $message);
    }

    /**
     * Send an OTP (One-Time Password) message.
     *
     * @param string $phoneNumber Recipient phone number
     * @param string $otp The OTP code
     * @param int|null $expiryMinutes OTP expiry time in minutes
     * @return array Standard response
     */
    public function sendOTP(string $phoneNumber, string $otp, ?int $expiryMinutes = null): array
    {
        $template = 'Your verification code is {otp}.';
        
        if ($expiryMinutes) {
            $template .= ' Valid for {expiry} minutes.';
        }
        
        $template .= ' Do not share this code.';

        return $this->sendTemplate($phoneNumber, $template, [
            'otp' => $otp,
            'expiry' => $expiryMinutes,
        ]);
    }

    /**
     * Send a notification message.
     *
     * @param string $phoneNumber Recipient phone number
     * @param string $title Notification title
     * @param string $body Notification body
     * @return array Standard response
     */
    public function sendNotification(string $phoneNumber, string $title, string $body): array
    {
        $message = "{$title}: {$body}";
        return $this->send($phoneNumber, $message);
    }

    /**
     * Check if SMS service is available and configured.
     *
     * @return bool
     */
    public function isAvailable(): bool
    {
        return $this->configService->isConfigured();
    }

    /**
     * Get SMS service status and statistics.
     *
     * @return array Status information
     */
    public function getStatus(): array
    {
        $configStatus = $this->configService->getStatus();
        
        return [
            'available' => $configStatus['configured'] && $configStatus['is_active'],
            'configured' => $configStatus['configured'],
            'environment' => $configStatus['environment'],
            'sender_id' => $configStatus['sender_id'],
        ];
    }

    /**
     * Validate a phone number without sending SMS.
     *
     * @param string $phoneNumber Phone number to validate
     * @return array Validation result with 'valid' and 'formatted' keys
     */
    public function validatePhone(string $phoneNumber): array
    {
        $validation = $this->provider->validatePhoneNumber($phoneNumber);
        
        if (!$validation['valid']) {
            return $validation;
        }

        return [
            'valid' => true,
            'formatted' => $this->provider->formatPhoneNumber($phoneNumber),
            'original' => $phoneNumber,
        ];
    }

    /**
     * Get the current SMS configuration for display purposes.
     * 
     * Note: Does not return sensitive data like API keys.
     *
     * @return array|null
     */
    public function getConfiguration(): ?array
    {
        return $this->configService->getStatus();
    }
}
