<?php

declare(strict_types=1);

namespace ApiModel\Infrastructure\Queue;

use ApiModel\Infrastructure\Logging\StructuredLog;
use ApiModel\Infrastructure\Mail\PhpMailerFactory;
use PHPMailer\PHPMailer\Exception as MailerException;
use PDO;

final class JobDispatcher
{
    public function __construct(
        private readonly ?PhpMailerFactory $mailFactory,
        private readonly PDO $pdo,
    ) {}

    /**
     * @param array<string,mixed> $payload
     */
    public function dispatch(string $type, array $payload): void
    {
        if ($type === 'auth.password_reset_email') {
            $this->sendPasswordResetMail($payload);
            return;
        }

        if ($type === 'notifications.insert_batch') {
            $this->insertNotificationBatch($payload);
            return;
        }

        throw new \RuntimeException('Tipo de job no soportado: ' . $type);
    }

    /**
     * @param array<string,mixed> $payload
     */
    private function insertNotificationBatch(array $payload): void
    {
        $raw = $payload['items'] ?? null;
        if (! is_array($raw) || $raw === []) {
            throw new \RuntimeException('Payload inválido para notifications.insert_batch');
        }

        $items = [];
        foreach ($raw as $row) {
            if (! is_array($row)) {
                throw new \RuntimeException('Item de notificación inválido');
            }
            $uid = trim((string) ($row['user_id'] ?? ''));
            $nType = trim((string) ($row['type'] ?? ''));
            $title = trim((string) ($row['title'] ?? ''));
            $body = trim((string) ($row['body'] ?? ''));
            if ($uid === '' || $nType === '' || $title === '' || $body === '') {
                throw new \RuntimeException('Campos obligatorios faltantes en notificación');
            }
            $claimId = $row['claim_id'] ?? null;
            $items[] = [
                'user_id' => $uid,
                'type' => $nType,
                'title' => $title,
                'body' => $body,
                'claim_id' => is_string($claimId) && $claimId !== '' ? $claimId : null,
            ];
        }

        InAppNotificationWriter::insertBatch($this->pdo, $items);
    }

    /**
     * @param array<string,mixed> $payload
     */
    private function sendPasswordResetMail(array $payload): void
    {
        $email = trim((string) ($payload['email'] ?? ''));
        $code = trim((string) ($payload['code'] ?? ''));
        $lang = strtolower(trim((string) ($payload['lang'] ?? 'es'))) === 'en' ? 'en' : 'es';

        if ($email === '' || $code === '') {
            throw new \RuntimeException('Payload inválido para auth.password_reset_email');
        }

        if ($this->mailFactory === null) {
            StructuredLog::emit('warning', 'queue.mail_skipped', [
                'reason' => 'mail_not_configured',
                'email' => $email,
            ]);
            return;
        }

        try {
            $mail = $this->mailFactory->createForNotifications();
            $mail->addAddress($email);

            // Intentar cargar la plantilla desde auth.messages
            $st = $this->pdo->prepare('SELECT subject_es, subject_en, body_html_es, body_html_en FROM auth.messages WHERE code = ?');
            $st->execute(['PASSWORD_RESET']);
            $template = $st->fetch();

            if ($template) {
                $mail->Subject = $lang === 'en' ? $template['subject_en'] : $template['subject_es'];
                $bodyHtml = $lang === 'en' ? $template['body_html_en'] : $template['body_html_es'];
                $mail->Body = str_replace('{{code}}', $code, $bodyHtml);
                $mail->isHTML(true);
            } else {
                $mail->Subject = $lang === 'en' ? 'Password recovery code' : 'Codigo de recuperacion de contrasena';
                $mail->Body = $lang === 'en' 
                    ? "Your recovery code is: {$code}\n\nIf you did not request this, please ignore this email."
                    : "Tu codigo de recuperacion es: {$code}\n\nSi no solicitaste este cambio, ignora este mensaje.";
            }

            $mail->send();
        } catch (MailerException $e) {
            throw new \RuntimeException('Error enviando correo: ' . $e->getMessage(), 0, $e);
        }
    }
}
