<?php

namespace App\Services\Notifications;

use App\Contracts\WhatsAppServiceContract;
use App\Models\User;
use App\Services\Settings\SettingService;
use App\Support\NotificationSettings;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Throwable;

class EventNotificationService
{
    public function __construct(
        private readonly SettingService $settings,
        private readonly WhatsAppServiceContract $whatsapp,
    ) {}

    /**
     * @param  array<string, string|null>  $variables
     */
    public function send(string $eventKey, User|string $recipient, array $variables = []): void
    {
        $email = $recipient instanceof User ? $recipient->email : (is_string($recipient) ? $recipient : null);
        $phone = $recipient instanceof User ? $recipient->phone : null;
        $name = $recipient instanceof User ? $recipient->name : null;

        $variables = array_merge($this->baseVariables($name, $email), $variables);

        if (NotificationSettings::isEmailEnabled($eventKey) && filled($email)) {
            $this->sendEmail($eventKey, $email, $variables);
        }

        if (NotificationSettings::isSmsEnabled($eventKey) && filled($phone)) {
            $this->sendSms($eventKey, $phone, $variables);
        }
    }

    /**
     * @param  array<string, string|null>  $variables
     */
    private function sendEmail(string $eventKey, string $email, array $variables): void
    {
        $subject = $this->render((string) NotificationSettings::get($eventKey, 'email_subject', ''), $variables);
        $body = $this->render((string) NotificationSettings::get($eventKey, 'email_body', ''), $variables);

        if ($subject === '' && $body === '') {
            return;
        }

        try {
            $this->applyMailConfig();

            Mail::html(nl2br(e($body)), function ($message) use ($email, $subject, $eventKey) {
                $message->to($email)
                    ->subject($subject !== '' ? $subject : NotificationSettings::label($eventKey));

                $message->getSymfonyMessage()
                    ->getHeaders()
                    ->addTextHeader('X-Platform-Notification', $eventKey);
            });
        } catch (Throwable $exception) {
            Log::warning('Event notification email failed.', [
                'event' => $eventKey,
                'email' => $email,
                'message' => $exception->getMessage(),
            ]);
        }
    }

    /**
     * @param  array<string, string|null>  $variables
     */
    private function sendSms(string $eventKey, string $phone, array $variables): void
    {
        if (! $this->whatsapp->isEnabled()) {
            return;
        }

        $body = $this->render((string) NotificationSettings::get($eventKey, 'sms_body', ''), $variables);

        if ($body === '') {
            return;
        }

        $this->whatsapp->send($phone, $body);
    }

    /**
     * @return array<string, string>
     */
    private function baseVariables(?string $name, ?string $email): array
    {
        return [
            'name' => $name ?? 'User',
            'email' => $email ?? '',
            'app_name' => (string) ($this->settings->get('app.name') ?? config('app.name')),
            'login_url' => route('login'),
        ];
    }

    /**
     * @param  array<string, string|null>  $variables
     */
    private function render(string $template, array $variables): string
    {
        $replacements = [];

        foreach ($variables as $key => $value) {
            $replacements['{'.$key.'}'] = (string) ($value ?? '');
        }

        return trim(strtr($template, $replacements));
    }

    private function applyMailConfig(): void
    {
        $host = (string) $this->settings->get('email.smtp_host', '');

        if ($host === '') {
            return;
        }

        Config::set('mail.default', 'smtp');
        Config::set('mail.from.address', $this->settings->get('email.from_address', config('mail.from.address')));
        Config::set('mail.from.name', $this->settings->get('email.from_name', config('mail.from.name')));
        Config::set('mail.mailers.smtp', [
            'transport' => 'smtp',
            'host' => $host,
            'port' => (int) $this->settings->get('email.smtp_port', 587),
            'encryption' => 'tls',
            'username' => $this->settings->get('email.smtp_username'),
            'password' => $this->settings->get('email.smtp_password'),
            'timeout' => null,
        ]);
    }
}
