<?php

namespace App\Domain\Subscription;

use App\Domain\WhatsApp\WhatsAppManager;
use App\Models\Subscription;
use App\Notifications\SubscriptionExpiringNotification;
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Notification;

/**
 * Multi-channel expiry notifications across a ladder of milestones
 * (7 days, 3 days, 1 day before; and on grace start). Each milestone fires
 * once per subscription — tracked in subscriptions.expiry_notified — across
 * WhatsApp + email + in-app simultaneously.
 */
class ExpiryNotifier
{
    /** milestone key => days before period end */
    public const LADDER = ['d7' => 7, 'd3' => 3, 'd1' => 1];

    public function __construct(protected WhatsAppManager $wa)
    {
    }

    public function run(): int
    {
        $sent = 0;
        $now = CarbonImmutable::now();

        Subscription::query()->withoutGlobalScope('tenant')
            ->whereIn('status', ['trialing', 'active'])
            ->where('current_period_ends_at', '>', $now)
            ->where('current_period_ends_at', '<=', $now->addDays(7))
            ->with(['tenant.users', 'plan'])->get()
            ->each(function (Subscription $sub) use ($now, &$sent) {
                $daysLeft = (int) ceil($now->diffInDays($sub->current_period_ends_at, false));
                $notified = $sub->expiry_notified ?? [];

                foreach (self::LADDER as $key => $threshold) {
                    if ($daysLeft <= $threshold && empty($notified[$key])) {
                        $this->dispatch($sub, $daysLeft);
                        $notified[$key] = $now->toIso8601String();
                        $sub->update(['expiry_notified' => $notified]);
                        $sent++;
                        break; // one milestone per run per sub
                    }
                }
            });

        return $sent;
    }

    protected function dispatch(Subscription $sub, int $daysLeft): void
    {
        $tenant = $sub->tenant;
        if (! $tenant) {
            return;
        }

        // In-app + email to clinic staff with billing access.
        $recipients = $tenant->users->filter(
            fn ($u) => $u->hasAnyRole(['clinic_owner']) || $u->can('billing.manage')
        );
        if ($recipients->isNotEmpty()) {
            Notification::send($recipients, new SubscriptionExpiringNotification($sub, $daysLeft));
        }

        // WhatsApp to the clinic's contact number (owner phone), trial-aware copy.
        $owner = $recipients->first();
        if ($owner?->phone) {
            $body = $sub->status === 'trialing'
                ? __('Your :clinic trial ends in :days day(s). Subscribe to keep your data and automations active: :link', [
                    'clinic' => $tenant->name, 'days' => $daysLeft, 'link' => $tenant->url('/billing'),
                ])
                : __('Your :clinic subscription renews in :days day(s). Renew here: :link', [
                    'clinic' => $tenant->name, 'days' => $daysLeft, 'link' => $tenant->url('/billing'),
                ]);

            // Use a lightweight raw send to the owner's number via a synthetic patient-less message.
            $this->wa->queueSystemMessage($tenant, $owner->phone, $body);
        }
    }
}
