<?php

namespace App\Services\Email;

use App\Models\Application;
use App\Models\ApplicationFollowUpReminder;
use App\Models\EmailDeliveryLog;
use App\Models\ImportedJob;
use App\Models\JobAlertPreference;
use App\Services\Notifications\DailyJobAlertMailer;
use Illuminate\Database\Eloquent\Collection;
use RuntimeException;

class EmailResendService
{
    public function __construct(
        private readonly DailyJobAlertMailer $dailyJobAlertMailer,
        private readonly TransactionalEmailSender $emailSender,
    ) {}

    public function resend(EmailDeliveryLog $log): EmailDeliveryLog
    {
        if (! $log->canBeResent()) {
            throw new RuntimeException('Only failed resendable emails can be resent.');
        }

        return match ($log->type) {
            EmailDeliveryLog::TYPE_JOB_ALERT => $this->resendJobAlert($log),
            EmailDeliveryLog::TYPE_APPLICATION_FOLLOW_UP => $this->resendApplicationFollowUp($log),
            default => throw new RuntimeException('This email type cannot be safely resent from the delivery log.'),
        };
    }

    private function resendJobAlert(EmailDeliveryLog $log): EmailDeliveryLog
    {
        $user = $log->user;
        $metadata = $log->metadata ?: [];
        $jobIds = array_values(array_filter((array) ($metadata['imported_job_ids'] ?? [])));

        if (! $user || $jobIds === []) {
            throw new RuntimeException('The original user or job list is missing.');
        }

        $preference = $user->jobAlertPreference ?: JobAlertPreference::query()->firstOrCreate(
            ['user_id' => $user->id],
            [
                'enabled' => true,
                'frequency' => 'daily',
                'minimum_match_score' => 45,
            ],
        );

        /** @var Collection<int, ImportedJob> $jobs */
        $jobs = ImportedJob::query()
            ->whereIn('id', $jobIds)
            ->get()
            ->sortBy(fn (ImportedJob $job): int => array_search($job->id, $jobIds, true) ?: 0)
            ->values();

        if ($jobs->isEmpty()) {
            throw new RuntimeException('No jobs from the original alert are still available.');
        }

        return $this->dailyJobAlertMailer->send($user, $preference, $jobs, [
            'resent_from_email_delivery_log_id' => $log->id,
        ]);
    }

    private function resendApplicationFollowUp(EmailDeliveryLog $log): EmailDeliveryLog
    {
        $metadata = $log->metadata ?: [];
        $application = Application::query()
            ->with(['user', 'importedJob'])
            ->find($metadata['application_id'] ?? null);
        $reminder = ApplicationFollowUpReminder::query()
            ->find($metadata['reminder_id'] ?? null);

        if (! $application || ! $application->user || ! $application->importedJob) {
            throw new RuntimeException('The original application follow-up data is missing.');
        }

        $job = $application->importedJob;
        $subject = 'Follow up on '.$job->title;
        $html = view('emails.applications.follow-up-reminder', [
            'subject' => $subject,
            'preheader' => 'A job application follow-up is due today.',
            'application' => $application,
            'job' => $job,
        ])->render();

        return $this->emailSender->send(
            toEmail: $application->user->email,
            toName: $application->user->name,
            subject: $subject,
            html: $html,
            text: "Your follow-up for {$job->title} is due. Open your pipeline: ".route('applications.pipeline'),
            userId: $application->user_id,
            type: EmailDeliveryLog::TYPE_APPLICATION_FOLLOW_UP,
            metadata: [
                'application_id' => $application->id,
                'reminder_id' => $reminder?->id,
                'imported_job_id' => $job->id,
                'resent_from_email_delivery_log_id' => $log->id,
            ],
            resendable: true,
        );
    }
}
