<?php

namespace App\Services;

use App\Models\AppNotification;
use App\Models\NotificationCampaign;
use App\Models\NotificationCampaignRecipient;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class TenantNotificationService
{
    public function __construct(
        private readonly SmsService $sms,
        private readonly WhatsappService $whatsapp,
        private readonly PlatformSettings $settings,
        private readonly EmailDeliveryLogger $emailLogs,
    ) {
    }

    public function send(array $data, User $sender): NotificationCampaign
    {
        $channels = collect($data['channels'] ?? [])
            ->intersect(['email', 'sms', 'portal', 'whatsapp'])
            ->values()
            ->all();

        $tenants = $this->resolveTenants($data);

        return DB::transaction(function () use ($data, $sender, $channels, $tenants): NotificationCampaign {
            $campaign = NotificationCampaign::create([
                'created_by' => $sender->id,
                'recipient_type' => 'tenant',
                'subject' => $data['subject'],
                'message' => $data['message'],
                'channels' => $channels,
                'audience_type' => $data['audience_type'],
                'audience_filters' => $this->audienceFilters($data),
                'status' => $tenants->isEmpty() ? 'no_recipients' : 'completed',
                'total_recipients' => $tenants->count(),
                'sent_at' => now(),
            ]);

            $emailSent = 0;
            $smsSent = 0;
            $portalAlerts = 0;
            $whatsappSent = 0;
            $failed = 0;

            foreach ($tenants as $tenant) {
                $recipient = NotificationCampaignRecipient::create([
                    'notification_campaign_id' => $campaign->id,
                    'tenant_id' => $tenant->id,
                    'tenant_name' => $tenant->name,
                    'email' => $tenant->email,
                    'phone' => $tenant->phone,
                    'sent_at' => now(),
                ]);

                if (in_array('portal', $channels, true)) {
                    AppNotification::withoutGlobalScopes()->create([
                        'tenant_id' => $tenant->id,
                        'title' => $data['subject'],
                        'body' => $data['message'],
                        'type' => 'platform',
                        'channel' => 'database',
                    ]);

                    $recipient->update(['portal_alert_status' => 'sent']);
                    $portalAlerts++;
                }

                if (in_array('email', $channels, true)) {
                    $emailResult = $this->sendEmail($tenant, $data['subject'], $data['message'], $campaign, $sender);
                    $recipient->update([
                        'email_status' => $emailResult['status'],
                        'email_error' => $emailResult['status'] === 'failed' ? $emailResult['message'] : null,
                    ]);

                    $emailResult['status'] === 'failed' ? $failed++ : $emailSent++;
                }

                if (in_array('sms', $channels, true)) {
                    $smsResult = filled($tenant->phone)
                        ? $this->sms->send($tenant->phone, $data['message'])
                        : ['status' => 'skipped', 'message' => 'Tenant has no phone number.'];

                    $recipient->update([
                        'sms_status' => $smsResult['status'],
                        'sms_error' => $smsResult['status'] === 'failed' ? $smsResult['message'] : null,
                    ]);

                    $smsResult['status'] === 'failed' ? $failed++ : $smsSent++;
                }

                if (in_array('whatsapp', $channels, true)) {
                    $whatsappResult = filled($tenant->phone)
                        ? $this->whatsapp->send($tenant->phone, $data['message'])
                        : ['status' => 'skipped', 'message' => 'Tenant has no phone number.'];

                    $recipient->update([
                        'whatsapp_status' => $whatsappResult['status'],
                        'whatsapp_error' => $whatsappResult['status'] === 'failed' ? $whatsappResult['message'] : null,
                    ]);

                    $whatsappResult['status'] === 'failed' ? $failed++ : $whatsappSent++;
                }
            }

            $campaign->update([
                'email_sent_count' => $emailSent,
                'sms_sent_count' => $smsSent,
                'portal_alert_count' => $portalAlerts,
                'whatsapp_sent_count' => $whatsappSent,
                'failed_count' => $failed,
                'status' => $failed > 0 ? 'completed_with_errors' : $campaign->status,
            ]);

            return $campaign;
        });
    }

    private function resolveTenants(array $data): Collection
    {
        $query = Tenant::query()->with('plan')->orderBy('name');

        match ($data['audience_type']) {
            'individual' => $query->whereIn('id', $data['tenant_ids'] ?? []),
            'status' => $this->applyStatusScope($query, $data['tenant_state'] ?? 'active'),
            'plan' => $query->where('subscription_plan_id', $data['plan_id'] ?? 0),
            default => null,
        };

        return $query->get()->unique('id')->values();
    }

    private function applyStatusScope(Builder $query, string $state): void
    {
        match ($state) {
            'active' => $query->activeAccess(),
            'trial' => $query->onTrial(),
            'new' => $query->newTenants(),
            'expired' => $query->expired(),
            'suspended' => $query->suspended(),
            default => $query->activeAccess(),
        };
    }

    private function audienceFilters(array $data): array
    {
        return [
            'tenant_ids' => $data['audience_type'] === 'individual' ? array_values($data['tenant_ids'] ?? []) : [],
            'tenant_state' => $data['audience_type'] === 'status' ? ($data['tenant_state'] ?? null) : null,
            'plan_id' => $data['audience_type'] === 'plan' ? ($data['plan_id'] ?? null) : null,
        ];
    }

    private function sendEmail(Tenant $tenant, string $subject, string $body, NotificationCampaign $campaign, User $sender): array
    {
        $baseLog = [
            'tenant_id' => $tenant->id,
            'notification_campaign_id' => $campaign->id,
            'user_id' => $sender->id,
            'source' => 'super_notification',
            'recipient_type' => 'tenant',
            'recipient_name' => $tenant->name,
            'recipient_email' => $tenant->email,
            'subject' => $subject,
            'body' => $body,
        ];

        if (blank($tenant->email)) {
            $this->emailLogs->record($baseLog + [
                'status' => 'skipped',
                'error_message' => 'Tenant has no email address.',
            ]);

            return ['status' => 'skipped', 'message' => 'Tenant has no email address.'];
        }

        $result = $this->settings->sendRawMail(null, $tenant->email, $tenant->name, $subject, $body);

        if ($result['status'] === 'sent') {
            $this->emailLogs->record($baseLog + [
                'status' => 'sent',
                'sent_at' => now(),
            ]);

            return $result;
        }

        $this->emailLogs->record($baseLog + [
            'status' => 'failed',
            'error_message' => $result['message'],
        ]);

        return $result;
    }
}
