<?php

namespace App\Services;

use App\Events\RenewalCompleted;
use App\Events\RenewalOpportunityCreated;
use App\Models\Application;
use App\Models\AuditLog;
use App\Models\CommunicationLog;
use App\Models\CorporateCompany;
use App\Models\CorporateDocument;
use App\Models\CorporateEmployeeDocument;
use App\Models\CrmActivity;
use App\Models\CustomerDocument;
use App\Models\CustomerIdentityRecord;
use App\Models\Employee;
use App\Models\EmployeeDocument;
use App\Models\RenewalOpportunity;
use App\Models\RenewalReminderLog;
use App\Models\RenewalReminderRule;
use App\Models\RenewalStatusHistory;
use App\Models\Service;
use App\Models\Tenant;
use App\Models\TenantDocument;
use App\Models\User;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

class RenewalService
{
    private const TRANSITIONS = [
        'upcoming' => ['reminder_scheduled', 'contacted', 'interested', 'lost'],
        'reminder_scheduled' => ['reminder_sent', 'contacted', 'interested', 'lost'],
        'reminder_sent' => ['contacted', 'interested', 'lost'],
        'contacted' => ['contacted', 'reminder_sent', 'interested', 'lost'],
        'interested' => ['application_created', 'lost'],
        'application_created' => ['completed', 'lost'],
        'completed' => [],
        'lost' => ['contacted'],
    ];

    public function __construct(
        private readonly FinancialNumberSequenceService $sequences,
        private readonly ApplicationService $applications,
    ) {}

    public function allowedTransitions(string $status): array
    {
        return self::TRANSITIONS[$status] ?? [];
    }

    public function scanTenant(Tenant $tenant, int $windowDays = 90): int
    {
        $created = 0;
        $cutoff = now()->addDays($windowDays)->endOfDay();

        CustomerDocument::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->where('is_current', true)
            ->whereNotNull('expiry_date')
            ->where('expiry_date', '<=', $cutoff)
            ->with(['customer', 'documentType'])
            ->chunkById(200, function ($documents) use ($tenant, &$created) {
                foreach ($documents as $document) {
                    $created += $this->createFromSource($tenant, [
                        'source_type' => 'customer_document',
                        'source_id' => $document->id,
                        'entity_type' => 'customer',
                        'customer_id' => $document->customer_id,
                        'branch_id' => $document->customer?->assigned_branch_id,
                        'document_type' => $document->documentType?->code ?? $document->document_name,
                        'document_number' => $document->document_number,
                        'expiry_date' => $document->expiry_date,
                    ]);
                }
            });

        CustomerIdentityRecord::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->where('is_current', true)
            ->whereNotNull('expiry_date')
            ->where('expiry_date', '<=', $cutoff)
            ->with('customer')
            ->chunkById(200, function ($records) use ($tenant, &$created) {
                foreach ($records as $record) {
                    $created += $this->createFromSource($tenant, [
                        'source_type' => 'customer_identity',
                        'source_id' => $record->id,
                        'entity_type' => 'customer',
                        'customer_id' => $record->customer_id,
                        'branch_id' => $record->customer?->assigned_branch_id,
                        'document_type' => $record->document_type,
                        'document_number' => $record->document_number,
                        'expiry_date' => $record->expiry_date,
                    ]);
                }
            });

        CorporateEmployeeDocument::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->whereNotNull('expiry_date')
            ->where('expiry_date', '<=', $cutoff)
            ->with('corporateEmployee')
            ->chunkById(200, function ($documents) use ($tenant, &$created) {
                foreach ($documents as $document) {
                    $created += $this->createFromSource($tenant, [
                        'source_type' => 'corporate_employee_document',
                        'source_id' => $document->id,
                        'entity_type' => 'corporate_employee',
                        'company_id' => $document->corporateEmployee?->company_id,
                        'corporate_employee_id' => $document->corporate_employee_id,
                        'document_type' => $document->document_type,
                        'document_number' => $document->document_number,
                        'expiry_date' => $document->expiry_date,
                    ]);
                }
            });

        CorporateDocument::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->whereNotNull('expiry_date')
            ->where('expiry_date', '<=', $cutoff)
            ->chunkById(200, function ($documents) use ($tenant, &$created) {
                foreach ($documents as $document) {
                    $created += $this->createFromSource($tenant, [
                        'source_type' => 'corporate_document',
                        'source_id' => $document->id,
                        'entity_type' => 'company',
                        'company_id' => $document->company_id,
                        'document_type' => $document->document_type,
                        'document_number' => $document->document_number,
                        'expiry_date' => $document->expiry_date,
                    ]);
                }
            });

        EmployeeDocument::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->where('reminder_enabled', true)
            ->whereNotNull('expiry_date')
            ->where('expiry_date', '<=', $cutoff)
            ->with('employee')
            ->chunkById(200, function ($documents) use ($tenant, &$created) {
                foreach ($documents as $document) {
                    $created += $this->createFromSource($tenant, [
                        'source_type' => 'employee_document',
                        'source_id' => $document->id,
                        'entity_type' => 'tenant_employee',
                        'employee_id' => $document->employee_id,
                        'branch_id' => $document->employee?->branch_id,
                        'document_type' => $document->document_type,
                        'document_number' => $document->document_number,
                        'expiry_date' => $document->expiry_date,
                    ]);
                }
            });

        TenantDocument::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->where('expiry_reminder_enabled', true)
            ->whereNotNull('expiry_date')
            ->where('expiry_date', '<=', $cutoff)
            ->chunkById(200, function ($documents) use ($tenant, &$created) {
                foreach ($documents as $document) {
                    $created += $this->createFromSource($tenant, [
                        'source_type' => 'tenant_document',
                        'source_id' => $document->id,
                        'entity_type' => 'company_compliance',
                        'document_type' => $document->document_type,
                        'document_number' => $document->document_number,
                        'expiry_date' => $document->expiry_date,
                    ]);
                }
            });

        CorporateCompany::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->whereNotNull('trade_license_expiry')
            ->where('trade_license_expiry', '<=', $cutoff)
            ->chunkById(200, function ($companies) use ($tenant, &$created) {
                foreach ($companies as $company) {
                    $created += $this->createFromSource($tenant, [
                        'source_type' => 'corporate_company_license',
                        'source_id' => $company->id,
                        'entity_type' => 'company',
                        'company_id' => $company->id,
                        'document_type' => 'trade_license',
                        'document_number' => $company->trade_license_number,
                        'expiry_date' => $company->trade_license_expiry,
                    ]);
                }
            });

        Employee::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->where(function ($query) use ($cutoff) {
                $query->where(fn ($passport) => $passport->whereNotNull('passport_expiry')->where('passport_expiry', '<=', $cutoff))
                    ->orWhere(fn ($visa) => $visa->whereNotNull('visa_expiry')->where('visa_expiry', '<=', $cutoff));
            })
            ->chunkById(200, function ($employees) use ($tenant, &$created) {
                foreach ($employees as $employee) {
                    foreach (['passport' => $employee->passport_expiry, 'visa' => $employee->visa_expiry] as $type => $expiry) {
                        if (! $expiry) {
                            continue;
                        }
                        $created += $this->createFromSource($tenant, [
                            'source_type' => "employee_{$type}_field",
                            'source_id' => $employee->id,
                            'entity_type' => 'tenant_employee',
                            'employee_id' => $employee->id,
                            'branch_id' => $employee->branch_id,
                            'document_type' => $type,
                            'document_number' => null,
                            'expiry_date' => $expiry,
                        ]);
                    }
                }
            });

        $this->ensureDefaultReminderRules($tenant);

        return $created;
    }

    public function transition(
        Tenant $tenant,
        RenewalOpportunity $opportunity,
        string $toStatus,
        ?User $user = null,
        ?string $notes = null,
        array $attributes = []
    ): RenewalOpportunity {
        if ($user) {
            $this->assertTenantUser($tenant, $user);
        }

        return DB::transaction(function () use ($tenant, $opportunity, $toStatus, $user, $notes, $attributes) {
            $locked = RenewalOpportunity::withoutGlobalScopes()
                ->where('tenant_id', $tenant->id)
                ->whereKey($opportunity->id)
                ->lockForUpdate()
                ->first();

            if (! $locked) {
                throw ValidationException::withMessages(['renewal' => 'Renewal does not belong to this tenant.']);
            }

            $allowed = self::TRANSITIONS[$locked->status] ?? [];
            if (! in_array($toStatus, $allowed, true)) {
                throw ValidationException::withMessages([
                    'status' => "Renewal cannot move from {$locked->status} to {$toStatus}.",
                ]);
            }

            $fromStatus = $locked->status;
            $update = array_intersect_key($attributes, array_flip([
                'assigned_user_id', 'next_followup_at', 'last_contacted_at', 'service_id', 'application_id', 'lost_reason',
            ]));
            if (! empty($update['assigned_user_id'])) {
                $assignedUserExists = User::query()
                    ->where('tenant_id', $tenant->id)
                    ->whereKey($update['assigned_user_id'])
                    ->exists();
                if (! $assignedUserExists) {
                    throw ValidationException::withMessages(['assigned_user_id' => 'Assigned user does not belong to this tenant.']);
                }
            }
            $update['status'] = $toStatus;
            if ($toStatus === 'completed') {
                $update['completed_at'] = now();
            }
            if ($toStatus === 'contacted') {
                $update['last_contacted_at'] = $update['last_contacted_at'] ?? now();
            }

            $locked->update($update);
            RenewalStatusHistory::create([
                'tenant_id' => $tenant->id,
                'renewal_opportunity_id' => $locked->id,
                'from_status' => $fromStatus,
                'to_status' => $toStatus,
                'notes' => $notes,
                'changed_by' => $user?->id,
            ]);

            AuditLog::record('renewals', 'renewal.status_changed', $locked, ['status' => $fromStatus], ['status' => $toStatus]);

            return $locked->fresh();
        }, 3);
    }

    public function recordFollowUp(
        Tenant $tenant,
        RenewalOpportunity $opportunity,
        User $user,
        string $activityType,
        string $notes,
        ?string $nextFollowupAt = null
    ): RenewalOpportunity {
        $updated = $this->transition($tenant, $opportunity, 'contacted', $user, $notes, [
            'last_contacted_at' => now(),
            'next_followup_at' => $nextFollowupAt,
        ]);

        CrmActivity::create([
            'tenant_id' => $tenant->id,
            'renewal_opportunity_id' => $updated->id,
            'activity_type' => $activityType,
            'notes' => $notes,
            'created_by' => $user->id,
            'scheduled_at' => $nextFollowupAt,
            'is_completed' => true,
        ]);

        return $updated;
    }

    public function updateDocumentStatus(
        Tenant $tenant,
        RenewalOpportunity $opportunity,
        User $user,
        array $attributes
    ): RenewalOpportunity {
        $this->assertTenantUser($tenant, $user);
        $allowedStatuses = ['active', 'expiring', 'expired', 'renewal_in_progress', 'renewed', 'on_hold', 'cancelled'];
        if (! in_array($attributes['document_status'], $allowedStatuses, true)) {
            throw ValidationException::withMessages(['document_status' => 'Invalid renewal document status.']);
        }

        return DB::transaction(function () use ($tenant, $opportunity, $user, $attributes) {
            $locked = RenewalOpportunity::withoutGlobalScopes()
                ->where('tenant_id', $tenant->id)
                ->whereKey($opportunity->id)
                ->lockForUpdate()
                ->firstOrFail();
            $old = $locked->only(['document_status', 'document_number', 'expiry_date', 'reminder_enabled']);
            $locked->update([
                'document_status' => $attributes['document_status'],
                'document_number' => $attributes['document_number'] ?? $locked->document_number,
                'expiry_date' => $attributes['expiry_date'] ?? $locked->expiry_date,
                'reminder_enabled' => (bool) ($attributes['reminder_enabled'] ?? false),
            ]);
            AuditLog::record('renewals', 'renewal.document_status_changed', $locked, $old, $locked->fresh()->only(array_keys($old)), $user);

            return $locked->fresh();
        }, 3);
    }

    public function scheduleReminder(
        Tenant $tenant,
        RenewalOpportunity $opportunity,
        User $user,
        string $channel,
        string $scheduledAt,
        ?string $notes = null
    ): RenewalReminderLog {
        $this->assertTenantUser($tenant, $user);
        $scheduled = Carbon::parse($scheduledAt);
        if ($scheduled->lt(now()->subMinute())) {
            throw ValidationException::withMessages(['scheduled_at' => 'Reminder time cannot be in the past.']);
        }

        return DB::transaction(function () use ($tenant, $opportunity, $user, $channel, $scheduled, $notes) {
            $locked = RenewalOpportunity::withoutGlobalScopes()
                ->where('tenant_id', $tenant->id)
                ->whereKey($opportunity->id)
                ->lockForUpdate()
                ->firstOrFail();
            $recipient = $this->resolveRecipient($locked->loadMissing(['customer.contact', 'company.contacts']), $channel);
            if (! $recipient) {
                throw ValidationException::withMessages(['channel' => 'The selected reminder channel has no consented recipient.']);
            }

            $days = (int) now()->startOfDay()->diffInDays($locked->expiry_date->copy()->startOfDay(), false);
            $log = RenewalReminderLog::withoutGlobalScopes()->create([
                'tenant_id' => $tenant->id,
                'renewal_opportunity_id' => $locked->id,
                'channel' => $channel,
                'recipient' => $recipient,
                'template_code' => 'manual_renewal_'.now()->format('YmdHis').'_'.Str::lower(Str::random(4)),
                'days_before_expiry' => $days,
                'scheduled_at' => $scheduled,
                'status' => 'scheduled',
                'sent_at' => $scheduled,
                'created_by' => $user->id,
                'notes' => $notes,
            ]);
            $locked->update([
                'reminder_enabled' => true,
                'next_reminder_at' => $scheduled,
                'reminder_channel' => $channel,
            ]);
            AuditLog::record('renewals', 'renewal.reminder_scheduled', $locked, null, [
                'reminder_id' => $log->id,
                'channel' => $channel,
                'scheduled_at' => $scheduled->toDateTimeString(),
            ], $user);

            return $log;
        }, 3);
    }

    public function createApplicationFromRenewal(
        Tenant $tenant,
        RenewalOpportunity $opportunity,
        Service $service,
        User $user
    ): Application {
        $this->assertTenantUser($tenant, $user);

        $locked = RenewalOpportunity::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->whereKey($opportunity->id)
            ->firstOrFail();

        if (! $locked->customer_id) {
            throw ValidationException::withMessages([
                'renewal' => 'This renewal needs a linked customer before an application can be created.',
            ]);
        }

        $tenantService = Service::query()->where('tenant_id', $tenant->id)->whereKey($service->id)->first();
        if (! $tenantService) {
            throw ValidationException::withMessages(['service_id' => 'Service does not belong to this tenant.']);
        }

        $customer = $locked->customer;
        $application = $this->applications->createApplication($tenant, $customer, $tenantService, [
            'branch_id' => $locked->branch_id ?? $user->default_branch_id,
            'company_id' => $locked->company_id,
            'priority' => $locked->priority === 'critical' ? 'urgent' : $locked->priority,
        ], $user);

        $this->transition($tenant, $locked, 'application_created', $user, 'Application created from renewal opportunity.', [
            'application_id' => $application->id,
            'service_id' => $tenantService->id,
        ]);

        return $application;
    }

    public function complete(Tenant $tenant, RenewalOpportunity $opportunity, User $user): RenewalOpportunity
    {
        $completed = $this->transition($tenant, $opportunity, 'completed', $user, 'Renewal cycle completed.');
        event(new RenewalCompleted($completed));

        return $completed;
    }

    public function dispatchDueReminders(Tenant $tenant): int
    {
        $this->ensureDefaultReminderRules($tenant);
        $rules = RenewalReminderRule::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->where('is_active', true)
            ->get();
        $opportunities = RenewalOpportunity::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->whereNotIn('status', ['completed', 'lost'])
            ->with(['customer.contact', 'company.contacts'])
            ->get();
        $created = $this->dispatchScheduledReminders($tenant);

        foreach ($opportunities as $opportunity) {
            $opportunityCreated = 0;
            $days = (int) now()->startOfDay()->diffInDays($opportunity->expiry_date->copy()->startOfDay(), false);
            foreach ($rules as $rule) {
                if ((int) $rule->days_before_expiry !== $days) {
                    continue;
                }
                if ($rule->document_type !== '*' && $rule->document_type !== $opportunity->document_type) {
                    continue;
                }

                $recipient = $this->resolveRecipient($opportunity, $rule->channel);
                if (! $recipient) {
                    continue;
                }

                $log = RenewalReminderLog::withoutGlobalScopes()->firstOrCreate([
                    'tenant_id' => $tenant->id,
                    'renewal_opportunity_id' => $opportunity->id,
                    'channel' => $rule->channel,
                    'recipient' => $recipient,
                    'template_code' => $rule->template_code,
                    'days_before_expiry' => $days,
                ], [
                    'status' => $rule->channel === 'in_app' ? 'sent' : 'queued',
                    'sent_at' => $rule->channel === 'in_app' ? now() : null,
                ]);

                if (! $log->wasRecentlyCreated) {
                    continue;
                }

                $created++;
                $opportunityCreated++;
                if ($rule->channel === 'in_app' && $opportunity->customer_id) {
                    CommunicationLog::withoutGlobalScopes()->create([
                        'tenant_id' => $tenant->id,
                        'customer_id' => $opportunity->customer_id,
                        'channel' => 'system',
                        'direction' => 'outbound',
                        'recipient' => $recipient,
                        'subject' => 'Document expiry reminder',
                        'summary' => "{$opportunity->document_type} expires on {$opportunity->expiry_date->format('d M Y')}",
                        'template_code' => $rule->template_code,
                        'message' => "Renewal reminder for {$opportunity->document_type}.",
                        'status' => 'sent',
                        'sent_at' => now(),
                    ]);
                }
            }

            if ($opportunityCreated > 0 && $opportunity->status === 'upcoming') {
                $this->transition($tenant, $opportunity, 'reminder_scheduled', null, 'Automated reminder scheduled.');
            }
        }

        return $created;
    }

    private function createFromSource(Tenant $tenant, array $data): int
    {
        /** @var CarbonInterface $expiry */
        $expiry = $data['expiry_date'];
        $documentType = Str::of((string) ($data['document_type'] ?: 'document'))->snake()->limit(100, '')->toString();
        $deduplicationKey = hash('sha256', implode(':', [
            $data['source_type'],
            $data['source_id'],
            $expiry->format('Y-m-d'),
        ]));

        return DB::transaction(function () use ($tenant, $data, $expiry, $documentType, $deduplicationKey) {
            $opportunity = RenewalOpportunity::withoutGlobalScopes()->firstOrCreate([
                'tenant_id' => $tenant->id,
                'deduplication_key' => $deduplicationKey,
            ], [
                'branch_id' => $data['branch_id'] ?? null,
                'renewal_number' => $this->sequences->next($tenant, 'renewal'),
                'entity_type' => $data['entity_type'],
                'source_type' => $data['source_type'],
                'source_id' => $data['source_id'],
                'customer_id' => $data['customer_id'] ?? null,
                'company_id' => $data['company_id'] ?? null,
                'corporate_employee_id' => $data['corporate_employee_id'] ?? null,
                'employee_id' => $data['employee_id'] ?? null,
                'document_type' => $documentType,
                'document_number' => $data['document_number'] ?? null,
                'document_status' => $expiry->copy()->startOfDay()->lt(today()) ? 'expired' : 'expiring',
                'expiry_date' => $expiry,
                'status' => 'upcoming',
                'priority' => $this->priorityFor($expiry),
                'reminder_enabled' => true,
            ]);

            if (! $opportunity->wasRecentlyCreated) {
                return 0;
            }

            RenewalStatusHistory::create([
                'tenant_id' => $tenant->id,
                'renewal_opportunity_id' => $opportunity->id,
                'from_status' => null,
                'to_status' => 'upcoming',
                'notes' => 'Created automatically from expiry source.',
            ]);
            event(new RenewalOpportunityCreated($opportunity));

            return 1;
        }, 3);
    }

    private function priorityFor(CarbonInterface $expiry): string
    {
        $days = now()->startOfDay()->diffInDays($expiry->copy()->startOfDay(), false);

        return match (true) {
            $days <= 0 => 'critical',
            $days <= 7 => 'urgent',
            $days <= 30 => 'high',
            default => 'medium',
        };
    }

    private function dispatchScheduledReminders(Tenant $tenant): int
    {
        $logs = RenewalReminderLog::withoutGlobalScopes()
            ->where('tenant_id', $tenant->id)
            ->where('status', 'scheduled')
            ->whereNotNull('scheduled_at')
            ->where('scheduled_at', '<=', now())
            ->with('opportunity')
            ->get();
        $dispatched = 0;

        foreach ($logs as $log) {
            DB::transaction(function () use ($tenant, $log, &$dispatched) {
                $locked = RenewalReminderLog::withoutGlobalScopes()
                    ->where('tenant_id', $tenant->id)
                    ->whereKey($log->id)
                    ->where('status', 'scheduled')
                    ->lockForUpdate()
                    ->first();
                if (! $locked) {
                    return;
                }

                $opportunity = RenewalOpportunity::withoutGlobalScopes()
                    ->where('tenant_id', $tenant->id)
                    ->find($locked->renewal_opportunity_id);
                $newStatus = $locked->channel === 'in_app' ? 'sent' : 'queued';
                $locked->update(['status' => $newStatus, 'sent_at' => now()]);

                if ($locked->channel === 'in_app' && $opportunity?->customer_id) {
                    CommunicationLog::withoutGlobalScopes()->create([
                        'tenant_id' => $tenant->id,
                        'customer_id' => $opportunity->customer_id,
                        'channel' => 'system',
                        'direction' => 'outbound',
                        'recipient' => $locked->recipient,
                        'subject' => 'Renewal reminder',
                        'summary' => "{$opportunity->document_type} expires on {$opportunity->expiry_date->format('d M Y')}",
                        'template_code' => $locked->template_code,
                        'message' => $locked->notes ?: "Renewal reminder for {$opportunity->document_type}.",
                        'status' => 'sent',
                        'sent_at' => now(),
                    ]);
                }

                if ($opportunity) {
                    $next = RenewalReminderLog::withoutGlobalScopes()
                        ->where('renewal_opportunity_id', $opportunity->id)
                        ->where('status', 'scheduled')
                        ->where('id', '!=', $locked->id)
                        ->orderBy('scheduled_at')->first();
                    $opportunity->update([
                        'last_reminder_at' => now(),
                        'next_reminder_at' => $next?->scheduled_at,
                        'reminder_channel' => $next?->channel,
                    ]);
                }
                $dispatched++;
            }, 3);
        }

        return $dispatched;
    }

    private function ensureDefaultReminderRules(Tenant $tenant): void
    {
        foreach ([90, 60, 30, 15, 7, 1, 0] as $days) {
            RenewalReminderRule::withoutGlobalScopes()->firstOrCreate([
                'tenant_id' => $tenant->id,
                'document_type' => '*',
                'days_before_expiry' => $days,
                'channel' => 'in_app',
            ], [
                'template_code' => 'renewal_expiry_reminder',
                'is_active' => true,
            ]);
        }
    }

    private function resolveRecipient(RenewalOpportunity $opportunity, string $channel): ?string
    {
        if ($opportunity->customer) {
            $contact = $opportunity->customer->contact;
            if (! $contact?->notification_consent) {
                return null;
            }

            return match ($channel) {
                'email' => $contact->email,
                'whatsapp' => $contact->whatsapp_number ?: $contact->normalized_mobile,
                'sms' => $contact->normalized_mobile,
                default => "customer:{$opportunity->customer_id}",
            };
        }

        if ($opportunity->company) {
            $contact = $opportunity->company->contacts->firstWhere('is_primary', true)
                ?? $opportunity->company->contacts->first();

            return match ($channel) {
                'email' => $contact?->email ?: $opportunity->company->email,
                'whatsapp' => $contact?->whatsapp ?: $opportunity->company->whatsapp,
                'sms' => $contact?->mobile ?: $opportunity->company->mobile,
                default => "company:{$opportunity->company_id}",
            };
        }

        if ($opportunity->employee_id) {
            return "employee:{$opportunity->employee_id}";
        }

        return 'tenant:'.$opportunity->tenant_id;
    }

    private function assertTenantUser(Tenant $tenant, User $user): void
    {
        if ((int) $user->tenant_id !== (int) $tenant->id) {
            throw ValidationException::withMessages(['tenant' => 'User is not authorized for this tenant.']);
        }
    }
}
