<?php

namespace App\Jobs;

use App\Events\ServiceBookingConfirmedEvent;
use App\Facades\Settings;
use Carbon\Carbon;
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\Log;
use Illuminate\Support\Facades\Mail;
use Mtc\Crm\Traits\RetrievesCustomerId;
use Mtc\MercuryDataModels\Booking;
use Mtc\MercuryDataModels\BookingAvailability;
use Mtc\MercuryDataModels\ProcessingLog;

class ProcessIncomingBookingJob implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;
    use RetrievesCustomerId;

    /**
     * Create a new job instance.
     */
    public function __construct(protected Booking $booking)
    {
        $this->onQueue('sync');
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        $this->booking->refresh();
        if (empty($this->booking->ingested_at) && $this->process()) {
            $this->booking->update([
                'ingested_at' => Carbon::now(),
                'customer_id' => $this->getCustomerId($this->booking->email, $this->getDetails()),
            ]);
        }
    }

    private function process(): bool
    {
        try {
            $this->notifyCustomer();
            $this->notifyTeam();

            ServiceBookingConfirmedEvent::dispatch($this->booking);
            return true;
        } catch (\Exception $exception) {
            Log::warning($exception->getMessage());
        }

        return false;
    }

    private function notifyCustomer(): void
    {
        if (empty($this->booking->email) || !filter_var($this->booking->email, FILTER_VALIDATE_EMAIL)) {
            $this->booking->recordProcessing(
                'customer-notification',
                ProcessingLog::STATUS_SKIPPED,
                null,
                'No valid customer email address on the booking'
            );
            return;
        }

        $confirmation_class = config('crm.new_booking_confirmation_email');
        try {
            Mail::to($this->booking->email)->send(new $confirmation_class($this->booking));
        } catch (\Throwable $exception) {
            $this->booking->recordProcessing(
                'customer-notification',
                ProcessingLog::STATUS_FAILED,
                null,
                $exception->getMessage()
            );
            throw $exception;
        }

        $this->booking->recordProcessing(
            'customer-notification',
            ProcessingLog::STATUS_SUCCESS,
            null,
            'Sent booking confirmation email to ' . $this->booking->email
        );
    }

    private function notifyTeam(): void
    {
        $recipients = $this->getRecipients();
        if (empty($recipients)) {
            $this->booking->recordProcessing(
                'team-notification',
                ProcessingLog::STATUS_SKIPPED,
                null,
                'No team email addresses configured'
            );
            return;
        }

        $class = config('crm.new_booking_email');
        try {
            collect($recipients)
                ->each(fn ($recipient) => Mail::to($recipient)->send(new $class($this->booking)));
        } catch (\Throwable $exception) {
            $this->booking->recordProcessing(
                'team-notification',
                ProcessingLog::STATUS_FAILED,
                null,
                $exception->getMessage()
            );
            throw $exception;
        }

        $this->booking->recordProcessing(
            'team-notification',
            ProcessingLog::STATUS_SUCCESS,
            null,
            'Sent booking notification email to ' . implode(', ', $recipients)
        );
    }

    private function getDetails(): array
    {
        return [
            'phone_number' => $this->booking->phone_number,
            'first_name' => $this->booking->first_name,
            'last_name' => $this->booking->last_name,
        ];
    }

    private function getRecipients(): array
    {
        $recipients = [];

        $location = BookingAvailability::query()->where('dealership_id', $this->booking->location_id)->first();
        if ($location && $location->email) {
            $recipients = explode(',', (string) $location->email);
        }

        if (empty($recipients)) {
            $recipients[] = Settings::get('app-contact-contact_email');
        }
        return array_filter($recipients, fn ($email) => $email && filter_var($email, FILTER_VALIDATE_EMAIL));
    }
}
