<?php

namespace App\Modules\Twilio\Services;

use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\App;
use App\Modules\Bookings\CustomerNotification;
use App\Models\Setting;
use Twilio\Rest\Client as TwilioClient;

class TwilioService implements TwilioServiceInterface
{
    protected ?TwilioClient $twilioClient = null;
    protected bool $isFakeMode;
    protected string $fromNumber;

    public function __construct()
    {
        $this->isFakeMode = App::environment('local', 'testing');
        $this->initializeTwilioClient();
    }

    /**
     * Send SMS message
     */
    public function sendSMS(string $to, string $message, ?string $from = null): array
    {
        try {
            $from = $from ?? $this->fromNumber;
            $to = $this->formatPhoneNumber($to);

            if (!$this->validatePhoneNumber($to)) {
                throw new Exception('Invalid phone number format');
            }

            // Return fake response in local/testing environments
            if ($this->isFakeMode) {
                return $this->createFakeResponse($to, $from, $message);
            }

            if (!$this->twilioClient) {
                throw new Exception('Twilio not configured. Please check your settings.');
            }

            $twilioMessage = $this->twilioClient->messages->create(
                $to,
                [
                    'from' => $from,
                    'body' => $message
                ]
            );

            Log::info('[TWILIO] SMS sent', [
                'sid' => $twilioMessage->sid,
                'to' => $to,
                'status' => $twilioMessage->status
            ]);

            return [
                'success' => true,
                'message_sid' => $twilioMessage->sid,
                'status' => $twilioMessage->status,
                'to' => $to,
                'from' => $from
            ];

        } catch (Exception $e) {
            Log::error('[TWILIO] SMS failed', [
                'to' => $to,
                'error' => $e->getMessage()
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Send SMS with task context
     */
    public function sendTaskSMS(int $taskId, string $to, string $message): array
    {
        try {
            Log::info('[TWILIO] Sending task SMS', ['task_id' => $taskId, 'to' => $to]);

            $result = $this->sendSMS($to, $message);

            if ($result['success']) {
                $notification = CustomerNotification::create([
                    'type' => 'sms',
                    'sent_to' => $to,
                    'message' => $message,
                    'task_id' => $taskId,
                    'subject' => 'Task SMS Notification',
                    'message_sid' => $result['message_sid'] ?? null
                ]);

                $result['notification_id'] = $notification->id;
            }

            return $result;

        } catch (Exception $e) {
            Log::error('[TWILIO] Failed to send task SMS', [
                'task_id' => $taskId,
                'error' => $e->getMessage()
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Send completion notification SMS
     */
    public function sendCompletionSMS(int $taskId, string $to, string $message): array
    {
        try {
            Log::info('[TWILIO] Sending completion SMS', ['task_id' => $taskId, 'to' => $to]);

            $result = $this->sendSMS($to, $message);

            if ($result['success']) {
                $notification = CustomerNotification::create([
                    'type' => 'sms',
                    'sent_to' => $to,
                    'message' => $message,
                    'task_id' => $taskId,
                    'subject' => 'Task Completion Notification',
                    'message_sid' => $result['message_sid'] ?? null
                ]);

                $result['notification_id'] = $notification->id;
            }

            return $result;

        } catch (Exception $e) {
            Log::error('[TWILIO] Failed to send completion SMS', [
                'task_id' => $taskId,
                'error' => $e->getMessage()
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Test SMS configuration
     */
    public function testSMS(string $to, string $message): array
    {
        return $this->sendSMS($to, $message);
    }

    /**
     * Get SMS delivery status
     */
    public function getDeliveryStatus(string $messageSid): array
    {
        try {
            if ($this->isFakeMode) {
                return [
                    'success' => true,
                    'status' => 'delivered',
                    'error_code' => null,
                    'error_message' => null
                ];
            }

            if (!$this->twilioClient) {
                throw new Exception('Twilio not configured');
            }

            $message = $this->twilioClient->messages($messageSid)->fetch();

            return [
                'success' => true,
                'status' => $message->status,
                'error_code' => $message->errorCode,
                'error_message' => $message->errorMessage
            ];

        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Get SMS history
     */
    public function getSMSHistory(array $filters = []): array
    {
        if ($this->isFakeMode) {
            return [
                'success' => true,
                'data' => [],
                'count' => 0
            ];
        }

        try {
            if (!$this->twilioClient) {
                throw new Exception('Twilio not configured');
            }

            $messages = $this->twilioClient->messages->read($filters);
            $history = [];

            foreach ($messages as $message) {
                $history[] = [
                    'sid' => $message->sid,
                    'from' => $message->from,
                    'to' => $message->to,
                    'body' => $message->body,
                    'status' => $message->status,
                    'date_sent' => $message->dateSent
                ];
            }

            return [
                'success' => true,
                'data' => $history,
                'count' => count($history)
            ];

        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Validate phone number format
     */
    public function validatePhoneNumber(string $phoneNumber): bool
    {
        // Basic validation - can be enhanced with more sophisticated validation
        $cleaned = preg_replace('/[^0-9+]/', '', $phoneNumber);
        return strlen($cleaned) >= 10 && strlen($cleaned) <= 15;
    }

    /**
     * Format phone number for Twilio
     */
    public function formatPhoneNumber(string $phoneNumber): string
    {
        // Remove all non-numeric characters except +
        $cleaned = preg_replace('/[^0-9+]/', '', $phoneNumber);
        
        // If UK number starts with 0, replace with +44
        if (preg_match('/^0/', $cleaned)) {
            $cleaned = preg_replace('/^0/', '+44', $cleaned);
        }
        
        // If no + prefix, assume it's a UK number
        if (!preg_match('/^\+/', $cleaned)) {
            $cleaned = '+44' . $cleaned;
        }
        
        return $cleaned;
    }

    /**
     * Initialize Twilio client
     */
    protected function initializeTwilioClient(): void
    {
        // Get credentials from settings (admin panel) with fallback to config
        $accountSid = Setting::get('integrations.twilio.account_sid') ?: config('twilio.account_sid');
        $authToken = Setting::get('integrations.twilio.auth_token') ?: config('twilio.auth_token');
        $this->fromNumber = Setting::get('integrations.twilio.from_number') ?: config('twilio.from_number') ?: '';

        // Only initialize client if not in fake mode and credentials are available
        if (!$this->isFakeMode && $accountSid && $authToken) {
            try {
                $this->twilioClient = new TwilioClient($accountSid, $authToken);
            } catch (Exception $e) {
                Log::error('[TWILIO] Failed to initialize client', ['error' => $e->getMessage()]);
                $this->twilioClient = null;
            }
        }
    }

    /**
     * Create fake response for testing
     */
    protected function createFakeResponse(string $to, string $from, string $message): array
    {
        $fakeSid = 'FAKE' . strtoupper(uniqid());
        
        Log::info('[TWILIO FAKE] SMS would be sent', [
            'sid' => $fakeSid,
            'to' => $to,
            'from' => $from,
            'message' => $message
        ]);

        return [
            'success' => true,
            'message_sid' => $fakeSid,
            'status' => 'queued',
            'to' => $to,
            'from' => $from
        ];
    }
} 