<?php

namespace App\Jobs;

use App\Integrations\Notification\NotificationGateway;
use App\Models\Invitation;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;

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

    public int $tries = 5;

    public $backoff = [10, 30, 60, 120, 300];

    public function __construct(public int $invitationId)
    {
        $this->onQueue('notifications');
    }

    public function handle(NotificationGateway $gateway): void
    {
        $invitation = Invitation::with(['family', 'inviter'])->find($this->invitationId);

        if (!$invitation) {
            return;
        }

        $url = $this->buildInvitationUrl($invitation->token);
        $message = $this->buildSmsMessage($invitation->family?->name, $url);

        $maskedToken = substr($invitation->token, 0, 8).'...';
        Log::info('Invitation dispatch started', [
            'invitation_id' => $invitation->id,
            'family_id' => $invitation->family_id,
            'inviter_user_id' => $invitation->inviter_user_id,
            'phone' => $invitation->phone,
            'email' => $invitation->email,
            'token' => $maskedToken,
            'accept_url' => $url,
        ]);

        if ($invitation->phone) {
            Log::info('Attempting to send SMS invitation', [
                'to' => $invitation->phone,
            ]);
            try {
                $gateway->sendSms($invitation->phone, $message);
                Log::info('SMS invitation sent successfully', [
                    'to' => $invitation->phone,
                ]);
            } catch (\Throwable $e) {
                Log::error('SMS invitation failed', [
                    'to' => $invitation->phone,
                    'error' => $e->getMessage(),
                ]);
                throw $e;
            }
        }

        if ($invitation->email) {
            $subject = $this->buildEmailSubject($invitation->family?->name);
            Log::info('Attempting to send Email invitation', [
                'to' => $invitation->email,
                'subject' => $subject,
            ]);
            try {
                $gateway->sendEmail(
                    $invitation->email,
                    $subject,
                    'emails.invitations.invite',
                    [
                        'invitation' => $invitation,
                        'acceptUrl' => $url,
                        'familyName' => $invitation->family?->name,
                        'inviterName' => $invitation->inviter?->name,
                        'appName' => Config::get('app.name', 'FamilyTree'),
                    ]
                );
                Log::info('Email invitation sent successfully', [
                    'to' => $invitation->email,
                ]);
            } catch (\Throwable $e) {
                Log::error('Email invitation failed', [
                    'to' => $invitation->email,
                    'error' => $e->getMessage(),
                ]);
                throw $e;
            }
        }
    }

    private function buildInvitationUrl(string $token): string
    {
        $frontend = Config::get('platform.frontend_url', Config::get('app.url'));
        $path = '/invitations/accept/'.$token;

        return rtrim($frontend, '/').$path;
    }

    private function buildSmsMessage(?string $familyName, string $url): string
    {
        $appName = Config::get('app.name', 'FamilyTree');
        $familyText = $familyName ? "{$familyName} family" : 'a family';

        return Str::limit("You've been invited to join {$familyText} on {$appName}. Accept here: {$url}", 140);
    }

    private function buildEmailSubject(?string $familyName): string
    {
        $appName = Config::get('app.name', 'FamilyTree');
        $familyText = $familyName ? "{$familyName} Family" : 'your family';

        return "Invitation to join {$familyText} on {$appName}";
    }
}
