<?php

declare(strict_types=1);

namespace MailerPress\Actions\ActionScheduler\Processors;

\defined('ABSPATH') || exit;

use DI\DependencyException;
use DI\NotFoundException;
use MailerPress\Core\Attributes\Action;
use MailerPress\Core\EmailManager\EmailServiceManager;
use MailerPress\Core\Enums\Tables;
use MailerPress\Core\Interfaces\JobInterface;
use MailerPress\Core\Kernel;
use MailerPress\Core\QueueManager;
use MailerPress\Jobs\SendEmailJob;
use MailerPress\Models\Contacts;

class ContactEmailChunk
{
    /**
     * Generate a secure tracking token from access_token and batch_id
     */
    private static function generateTrackingToken(string $accessToken, int $batchId): string
    {
        // Use HMAC to create a secure token that includes batch_id
        $secret = defined('AUTH_SALT') ? AUTH_SALT : 'mailerpress-tracking-secret';
        $data = $accessToken . '|' . $batchId;
        $token = hash_hmac('sha256', $data, $secret);

        // Encode the token and batch_id together (base64url safe)
        $payload = base64_encode($token . '|' . $batchId);
        return rtrim(strtr($payload, '+/', '-_'), '=');
    }

    /**
     * @throws NotFoundException
     * @throws DependencyException
     * @throws \Exception
     */
    #[Action('mailerpress_process_contact_chunk', priority: 10, acceptedArgs: 2)]
    public function mailerpress_process_contact_chunk($batch_id, $transient_key): void
    {
        global $wpdb;

        $transient = get_transient($transient_key);

        if (false === $transient) {
            // Transient expired or missing - mark batch as failed
            $this->markBatchAsFailed($batch_id, 'Transient expired or missing');
            return;
        }

        $contact_chunk = $transient['contacts'];
        $html = $transient['html'];

        $sendingService = Kernel::getContainer()->get(EmailServiceManager::class)->getConfigurations();

        if ('mailerpress' === $sendingService['default_service']) {
            try {
                $service = Kernel::getContainer()->get(EmailServiceManager::class)->getServiceByKey($sendingService['default_service']);
                if (method_exists($service, 'createBatchSending')) {
                    $service->createBatchSending(
                        $transient,
                        $batch_id
                    );
                }
            } catch (\Throwable $e) {
                // If service fails, mark batch as failed
                $this->markBatchAsFailed($batch_id, 'Service error: ' . $e->getMessage());
                return;
            }
        } else {
            /** @var JobInterface $process */
            $process = new SendEmailJob([
                'transient_key' => $transient_key,
                'subject' => $transient['subject'] ?? '',
                'sender_name' => $transient['sender_name'],
                'sender_to' => $transient['sender_to'],
                'api_key' => $transient['api_key'],
                'body' => $html,
                'to' => array_reduce(
                    $contact_chunk,
                    static function ($carry, $item) use ($batch_id, $transient) {
                        $contactEntity = Kernel::getContainer()->get(Contacts::class)->get((int)$item);
                        $carry[] = [
                            'email' => Kernel::getContainer()->get(Contacts::class)->get((int)$item)->email,
                            'id' => (int) $contactEntity->contact_id, // ✅ add this
                            'campaign_id' => (int) $transient['campaignId'], // ✅ add this
                            'variables' => [
                                'TRACK_CLICK' => home_url('/'), // your redirect endpoint
                                'CONTACT_ID'  => (int) $contactEntity->contact_id,
                                'CAMPAIGN_ID' => (int) $transient['campaignId'],
                                'UNSUB_LINK' => wp_unslash(
                                    \sprintf(
                                        '%s&data=%s&cid=%s&batchId=%s',
                                        mailerpress_get_page('unsub_page'),
                                        esc_attr($contactEntity->unsubscribe_token),
                                        esc_attr($contactEntity->access_token),
                                        $batch_id
                                    )
                                ),
                                'MANAGE_SUB_LINK' => wp_unslash(
                                    \sprintf(
                                        '%s&cid=%s',
                                        mailerpress_get_page('manage_page'),
                                        esc_attr($contactEntity->access_token)
                                    )
                                ),
                                'CONTACT_NAME' => esc_html($contactEntity->first_name) . ' ' . esc_html($contactEntity->last_name),
                                'TRACK_OPEN' => get_rest_url(
                                    null,
                                    \sprintf(
                                        'mailerpress/v1/campaign/track-open?token=%s',
                                        \MailerPress\Core\HtmlParser::generateTrackOpenToken(
                                            (int) $contactEntity->contact_id,
                                            (int) $transient['campaignId'],
                                            (int) $batch_id
                                        )
                                    )
                                ),
                                'contact_name' => \sprintf(
                                    '%s %s',
                                    esc_html($contactEntity->first_name),
                                    esc_html($contactEntity->last_name)
                                ),
                                'contact_email' => \sprintf('%s', esc_html($contactEntity->email)),
                                'contact_first_name' => \sprintf('%s', esc_html($contactEntity->first_name)),
                                'contact_last_name' => \sprintf('%s', esc_html($contactEntity->last_name)),
                            ],
                        ];

                        // Add custom fields to variables
                        global $wpdb;
                        $customFieldsTable = Tables::get(Tables::MAILERPRESS_CONTACT_CUSTOM_FIELDS);
                        $customFields = $wpdb->get_results($wpdb->prepare(
                            "SELECT field_key, field_value FROM {$customFieldsTable} WHERE contact_id = %d",
                            (int) $contactEntity->contact_id
                        ));

                        if ($customFields) {
                            foreach ($customFields as $customField) {
                                // Add custom field to variables using field_key as the key
                                $carry[count($carry) - 1]['variables'][$customField->field_key] = esc_html($customField->field_value ?? '');
                            }
                        }

                        return $carry;
                    },
                    []
                ),
                'webhook_url' => $transient['webhook_url'],
                'scheduled_at' => $transient['scheduled_at'],
                'batch_id' => $batch_id,
                'sendType' => $transient['sendType'],
                'timestamp' => time(),
            ]);

            try {
                QueueManager::getInstance()->registerJob($process);
                do_action('mailerpress_process_queue_worker');
            } catch (\Throwable $e) {
                // If job registration fails, mark batch as failed
                $this->markBatchAsFailed($batch_id, 'Failed to register email job: ' . $e->getMessage());
            }
        }
    }

    /**
     * Mark batch and campaign as failed
     */
    private function markBatchAsFailed(int $batch_id, string $error_message): void
    {
        global $wpdb;

        $batchTable = Tables::get(Tables::MAILERPRESS_EMAIL_BATCHES);
        $campaignTable = Tables::get(Tables::MAILERPRESS_CAMPAIGNS);

        // Get batch info to find campaign_id
        $batch = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT campaign_id FROM {$batchTable} WHERE id = %d",
                $batch_id
            )
        );

        if ($batch) {
            // Update batch status to failed
            $wpdb->update(
                $batchTable,
                [
                    'status' => 'failed',
                    'updated_at' => current_time('mysql'),
                ],
                ['id' => $batch_id],
                ['%s', '%s'],
                ['%d']
            );

            // Update campaign status to error
            $wpdb->update(
                $campaignTable,
                [
                    'status' => 'error',
                    'updated_at' => current_time('mysql'),
                ],
                ['campaign_id' => (int) $batch->campaign_id],
                ['%s', '%s'],
                ['%d']
            );
        }
    }
}
