<?php

declare(strict_types=1);

namespace MailerPress\Jobs;

\defined('ABSPATH') || exit;

use MailerPress\Core\Abstract\BaseJob;
use MailerPress\Core\EmailManager\EmailServiceManager;
use MailerPress\Core\Enums\Tables;
use MailerPress\Core\HtmlParser;
use MailerPress\Core\Kernel;
use Throwable;
use WP_Error;

class SendEmailJob extends BaseJob
{
    /**
     * @param array{
     *   to: array<int, array{email:string,variables:array<string,mixed>}>,
     *   subject: string,
     *   sender_to: string,
     *   sender_name: string,
     *   body: string,
     *   webhook_url?: string,
     *   batch_id?: int|string,
     *   transient_key?: string
     * } $data
     */
    public function handle(array $data): void
    {
        $countSuccess = 0;
        $countError = 0;
        $errors = []; // collect per-recipient error detail (optional)

        // We'll want to know if the whole job failed catastrophically
        $jobException = null;

        try {
            $recipientBatches = $data['to']; // you said already chunked to <= 50 items

            // Acquire shared services once outside loop.
            $container = Kernel::getContainer();
            /** @var HtmlParser $parser */
            $parser = $container->get(HtmlParser::class);
            /** @var EmailServiceManager $manager */
            $manager = $container->get(EmailServiceManager::class);
            $mailer = $manager->getActiveService();

            $apiKey = '';

            $servicesData = get_option('mailerpress_email_services', []);

            if (
                !empty($servicesData['default_service'])
                && !empty($servicesData['services'][$servicesData['default_service']]['conf']['api_key'])
            ) {
                $defaultService = $servicesData['default_service'];
                $apiKey = $servicesData['services'][$defaultService]['conf']['api_key'];
            }

            // Récupérer les paramètres Reply to depuis les paramètres par défaut
            $defaultSettings = get_option('mailerpress_default_settings', []);
            if (is_string($defaultSettings)) {
                $defaultSettings = json_decode($defaultSettings, true) ?: [];
            }

            // Déterminer les valeurs Reply to (utiliser From si Reply to est vide)
            $replyToName = !empty($defaultSettings['replyToName'])
                ? $defaultSettings['replyToName']
                : ($data['sender_name'] ?? '');
            $replyToAddress = !empty($defaultSettings['replyToAddress'])
                ? $defaultSettings['replyToAddress']
                : ($data['sender_to'] ?? '');

            foreach ($recipientBatches as $recipient) {
                try {
                    // Render per‑recipient body
                    $body = $parser->init(
                        $data['body'],
                        $recipient['variables'] ?? []
                    )->replaceVariables();

                    $result = $mailer->sendEmail([
                        'to' => $recipient['email'],
                        'html' => true,
                        'body' => $body,
                        'subject' => $data['subject'],
                        'sender_name' => $data['sender_name'] ?? '',
                        'sender_to' => $data['sender_to'] ?? '',
                        'reply_to_name' => $replyToName,
                        'reply_to_address' => $replyToAddress,
                        'apiKey' => $apiKey,
                    ]);

                    // --- Insert default stats row if not exists ---
                    if (!empty($recipient['id']) && !empty($recipient['campaign_id'])) {
                        global $wpdb;
                        $contactStatsTable = Tables::get(Tables::MAILERPRESS_CONTACT_STATS);

                        $exists = $wpdb->get_var($wpdb->prepare(
                            "SELECT id FROM {$contactStatsTable} WHERE contact_id = %d AND campaign_id = %d",
                            $recipient['id'],
                            $recipient['campaign_id']
                        ));

                        if (!$exists) {
                            $wpdb->insert(
                                $contactStatsTable,
                                [
                                    'contact_id' => $recipient['id'],
                                    'campaign_id' => $recipient['campaign_id'],
                                    'opened' => 0,
                                    'clicked' => 0,
                                    'click_count' => 0,
                                    'last_click_at' => null,
                                    'revenue' => 0,
                                    'status' => 'neutral',
                                    'created_at' => current_time('mysql'),
                                    'updated_at' => current_time('mysql'),
                                ],
                                ['%d', '%d', '%d', '%d', '%d', '%s', '%f', '%s', '%s', '%s']
                            );
                        }
                    }

                    if ($result === true) {
                        ++$countSuccess;
                        // Note: La mise à jour de sent_emails se fait maintenant à la fin du traitement pour éviter les problèmes de concurrence
                    } else {
                        ++$countError;

                        $errorMessage = 'Mailer returned false.';
                        if ($result instanceof \WP_Error) {
                            $errorMessage = $result->get_error_message();
                        }

                        $errors[] = [
                            'email' => $recipient['email'],
                            'message' => $errorMessage,
                        ];
                        // Note: La mise à jour de error_emails se fait maintenant à la fin du traitement pour éviter les problèmes de concurrence

                        // --- Log to file per batch ---
                        $batchId = $data['batch_id'] ?? 'unknown';
                        $logDir = WP_CONTENT_DIR . '/mailerpress-logs';
                        $logFile = $logDir . "/batch-{$batchId}.log";

                        if (!is_dir($logDir)) {
                            wp_mkdir_p($logDir);
                        }

                        $logEntry = sprintf(
                            "[%s] Email: %s | Error: %s\n",
                            current_time('mysql'),
                            $recipient['email'],
                            $errorMessage
                        );

                        file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
                    }
                } catch (Throwable $e) {
                    ++$countError;
                    $errors[] = [
                        'email' => $recipient['email'] ?? '',
                        'message' => $e->getMessage(),
                    ];

                    // --- Log to file per batch ---
                    $batchId = $data['batch_id'] ?? 'unknown';

                    $logDir = WP_CONTENT_DIR . '/mailerpress-logs';
                    $logFile = $logDir . "/batch-{$batchId}.log";

                    if (!is_dir($logDir)) {
                        wp_mkdir_p($logDir); // creates dir safely with proper perms
                    }

                    $logEntry = sprintf(
                        "[%s] Email: %s | Error: %s\n",
                        current_time('mysql'),
                        $recipient['email'] ?? 'N/A',
                        $e->getMessage()
                    );

                    file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
                }
            }

            // Mettre à jour sent_emails et error_emails en une seule fois à la fin (plus efficace et évite les problèmes de concurrence)
            if (!empty($data['batch_id']) && ($countSuccess > 0 || $countError > 0)) {
                global $wpdb;
                $batchTable = Tables::get(Tables::MAILERPRESS_EMAIL_BATCHES);
                $batch_id = (int) $data['batch_id'];

                // Mettre à jour sent_emails et error_emails en une seule requête
                if ($countSuccess > 0) {
                    $updated = $wpdb->query(
                        $wpdb->prepare(
                            "UPDATE {$batchTable} SET sent_emails = COALESCE(sent_emails, 0) + %d WHERE id = %d",
                            $countSuccess,
                            $batch_id
                        )
                    );
                }

                if ($countError > 0) {
                    $updated = $wpdb->query(
                        $wpdb->prepare(
                            "UPDATE {$batchTable} SET error_emails = COALESCE(error_emails, 0) + %d WHERE id = %d",
                            $countError,
                            $batch_id
                        )
                    );
                }

                // Vérifier si tous les emails sont envoyés et mettre à jour le statut du batch à 'sent'
                $batch = $wpdb->get_row(
                    $wpdb->prepare(
                        "SELECT total_emails, sent_emails, error_emails, status, campaign_id FROM {$batchTable} WHERE id = %d",
                        $batch_id
                    ),
                    ARRAY_A
                );

                if ($batch && $batch['status'] !== 'sent') {
                    $total_emails = (int) ($batch['total_emails'] ?? 0);
                    $sent_emails = (int) ($batch['sent_emails'] ?? 0);
                    $error_emails = (int) ($batch['error_emails'] ?? 0);
                    $campaign_id = (int) ($batch['campaign_id'] ?? 0);

                    // Si tous les emails sont envoyés (succès + erreurs = total)
                    if ($total_emails > 0 && ($sent_emails + $error_emails) >= $total_emails) {
                        // Mettre à jour le statut du batch à 'sent'
                        $wpdb->update(
                            $batchTable,
                            ['status' => 'sent', 'updated_at' => current_time('mysql')],
                            ['id' => $batch_id],
                            ['%s', '%s'],
                            ['%d']
                        );

                        // Déclencher le hook pour mettre à jour le statut de la campagne
                        do_action('mailerpress_batch_event', 'sent', $campaign_id, $batch_id);
                    } elseif ($batch['status'] === 'pending' || $batch['status'] === 'scheduled') {
                        // Mettre à jour le statut à 'in_progress' si ce n'est pas déjà le cas
                        $wpdb->update(
                            $batchTable,
                            ['status' => 'in_progress', 'updated_at' => current_time('mysql')],
                            ['id' => $batch_id],
                            ['%s', '%s'],
                            ['%d']
                        );

                        // Déclencher le hook pour mettre à jour le statut de la campagne
                        do_action('mailerpress_batch_event', 'in_progress', $campaign_id, $batch_id);
                    }
                }
            }
        } catch (Throwable $e) {
            // This means something big failed (config, container, parsing, etc.)
            $countSuccess = 0;
            $countError = count($data['to']);
        } finally {
            if (
                \array_key_exists('webhook_url', $data)
                && \array_key_exists('batch_id', $data)
            ) {
                $this->sendNotification(
                    $data['webhook_url'],
                    [
                        'action' => 'batch_update',
                        'batch_id' => $data['batch_id'],
                        'countSent' => [
                            'success' => $countSuccess,
                            'error' => $countError,
                        ],
                        // optional: pass transient key for cleanup
                        'transient_key' => $data['transient_key'] ?? null,
                    ]
                );
            }
        }

        // If the job blew up, rethrow so the queue system can mark it failed / retry.
        if ($jobException) {
            throw $jobException; // Action Scheduler will log failure & retry per its rules
        }
    }

    /**
     * Post a JSON webhook and optionally clear transient.
     */
    private function sendNotification(string $url, array $payload): void
    {
        if (!empty($payload['transient_key'])) {
            delete_transient($payload['transient_key']);
        }

        $args = [
            'headers' => [
                'Content-Type' => 'application/json',
            ],
            'body' => wp_json_encode($payload),
            'timeout' => 15, // be explicit; default 5s may be too low at scale
        ];

        wp_remote_post($url, $args);
    }
}
