<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use RuntimeException;

class SendSmsMessage implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(public int $messageId) {}

    public function handle()
    {
        $msg = \App\Models\SmsMessage::with(['recipients'])->findOrFail($this->messageId);
        $msg->update(['status' => 'processing']);

        foreach ($msg->recipients as $r) {
            if (in_array($r->status, ['sent', 'failed'])) continue;

            try {
                $phone = $r->phone;
                $message = $msg->content;

                $params = array(
                    'to'            => '+39' . $phone,
                    'from'          => env('SMS_FROM', 'Leezard'),
                    'message'       => $message,
                    'format'        => 'json',
                );
                $this->sms_send($params);

                $r->update(['status' => 'sent', 'sent_at' => now(), 'error_message' => null]);
            } catch (\Throwable $e) {
                $r->update(['status' => 'failed', 'error_message' => $e->getMessage()]);
            }
        }
        $total = $msg->recipients()->count();
        $sent = $msg->recipients()->where('status', 'sent')->count();
        $failed = $msg->recipients()->where('status', 'failed')->count();

        $newStatus = 'draft';
        if ($total === 0) {
            $newStatus = 'draft';
        } elseif ($sent === $total) {
            $newStatus = 'sent';
        } elseif ($sent > 0 && $failed > 0) {
            $newStatus = 'partial';
        } else {
            $newStatus = 'failed';
        }

        $msg->update([
            'status' => $newStatus,
            'sent_at' => $sent > 0 ? now() : $msg->sent_at,
        ]);
    }

    public function sms_send(array $params, bool $backup = false)
    {
        if (!isset($params['format'])) {
            $params['format'] = 'json';
        }

        $url = $backup
            ? 'https://api2.smsapi.com/sms.do'
            : 'https://api.smsapi.com/sms.do';

        $ch = curl_init($url);

        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $params,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . env('SMS_TOKEN'),
            ],
            CURLOPT_TIMEOUT => 15,
            CURLOPT_CONNECTTIMEOUT => 5,
        ]);

        $content = curl_exec($ch);
        $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_error($ch);

        curl_close($ch);

        if ($content === false) {
            if (!$backup) {
                return $this->sms_send($params, true);
            }

            throw new RuntimeException('SMS API cURL error: ' . $curlError);
        }

        if ($httpStatus !== 200) {
            if (!$backup && $httpStatus >= 500 && $httpStatus < 600) {
                return $this->sms_send($params, true);
            }

            throw new RuntimeException("SMS API HTTP {$httpStatus}: {$content}");
        }

        $data = json_decode($content, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new RuntimeException('SMS API invalid JSON response: ' . $content);
        }

        if (isset($data['error'])) {
            $msg = is_array($data['error'])
                ? ($data['error']['message'] ?? json_encode($data['error']))
                : $data['error'];

            throw new RuntimeException('SMS API error: ' . $msg);
        }

        if (isset($data['list'][0]['status'])) {
            $status = strtoupper($data['list'][0]['status']);

            if (in_array($status, ['ERROR', 'FAILED', 'REJECTED'], true)) {
                $errMsg = $data['list'][0]['error_message'] ?? 'Unknown SMS API error';
                throw new RuntimeException("SMS API message error ({$status}): {$errMsg}");
            }
        }

        return $data;
    }
}
