<?php

namespace Vendtics\App\Jobs;

use Exception;
use Vendtics\WpMVC\View\View;

defined( "ABSPATH" ) || exit;

use Vendtics\App\Repositories\ContactRepository;
use Vendtics\App\Repositories\CampaignRecipientRepository;
use Vendtics\App\DTO\Campaign\Recipient\DTO;
use Vendtics\App\Models\CampaignRecipient;
use stdClass;

class Campaign extends Jobs {
    /**
     * @var string
     */
    protected $action = 'campaign';

    protected CampaignRecipientRepository $recipient_repository;

    protected ContactRepository $contact_repository;

    protected $vend_task = [];

    public function __construct() {
        $this->recipient_repository = vendtics_singleton( CampaignRecipientRepository::class );
        $this->contact_repository   = vendtics_singleton( ContactRepository::class );
        register_shutdown_function( [$this, 'handle_fatal_errors'] );

        parent::__construct();
    }

    public function handle_fatal_errors() {
        $error = error_get_last();

        if ( $error && ! empty( $this->vend_task ) ) {
            vendtics_campaign_repository()->mark_as_paused(
                $this->vend_task['campaign']->id, [
                    'failed_source' => $this->get_wp_directory_info( $error['file'] ),
                    'error'         => $error
                ]
            );
        }
    }

    /**
     * Perform task with queued item.
     *
     * Override this method to perform any actions required on each
     * queue item. Return the modified item for further processing
     * in the next pass through. Or, return false to remove the
     * item from the queue.
     *
     * @param mixed $item Queue item to iterate over.
     *
     * @return mixed
     */
    protected function task( $item ) {
        $this->vend_task = $item;

        // Manage email sending frequency
        $current_time         = time();
        $per_email_seconds    = $this->vend_task['per_email_seconds'];
        $last_email_sent_time = $this->vend_task['last_email_sent_time'];
        $next_email_sent_time = ( $last_email_sent_time + $per_email_seconds ) - 1;
        $next_email_has_time  = $next_email_sent_time - $current_time;

        $rest_time = $this->get_rest_time();

        if ( 0 <= $next_email_has_time ) {
            if ( $next_email_has_time <= $rest_time ) {
                sleep( $next_email_has_time );
                return $this->vend_task;
            } else if ( $next_email_has_time > $rest_time ) { 
                sleep( $rest_time );
                return $this->vend_task;
            }
        }

        $campaign = $item['campaign'];

        try {
            $contact = $this->recipient_repository->get_recipient_query( $campaign )->select( 'contact.*' )->left_join( CampaignRecipient::get_table_name() . ' as recipient', 'recipient.contact_id', 'contact.id' )
            ->group_by( 'contact.id' )
            ->having( "SUM(COALESCE(recipient.campaign_id = $campaign->id, 0))", 0 ) // Exclude contacts if already in campaign recipient list
            ->first();
        } catch ( Exception $exception ) {
            vendtics_campaign_repository()->mark_as_paused(
                $campaign->id, [
                    'error' => $exception->getMessage()
                ]
            );
            return false;
        }

        if ( ! $contact ) {
            $this->complete_campaign( $campaign );
            return false;
        }

        $this->standard( $contact );

        $this->vend_task['last_email_sent_time'] = $current_time;

        return $this->vend_task;
    }

    protected function standard( stdClass $contact ) {
        $campaign = $this->vend_task['campaign'];

        $body    = vendtics_bind_dynamic_values( $campaign->body, $contact, $campaign );
        $subject = vendtics_bind_dynamic_values( $campaign->subject, $contact, $campaign );

        $body = $this->bind_open_tracker( $this->bind_click_tracker( $body, $contact ), $contact );

        $body = View::get( 'classic-email', compact( 'body' ) );

        $mailer = new \Vendtics\App\Mail\Campaign();
        $mailer->set_to( $contact->email )->set_subject( $subject )->set_body( $body )->send();

        $recipient_dto = ( new DTO )->set_campaign_id( $campaign->id )->set_contact_id( $contact->id );

        $this->recipient_repository->create( $recipient_dto );

        return $this->vend_task;
    }

    protected function bind_open_tracker( string $body, stdClass $contact ) {
        $campaign = $this->vend_task['campaign'];

        if ( 0 == $campaign->tracking_open_read ) {
            return $body;
        }

        $open_token = vendtics_generate_jwt_token( ["contact_id" => $contact->id, 'campaign_id' => $campaign->id] );
        $src        = add_query_arg( ['token' => $open_token], get_rest_url( null, "vendtics/campaigns/email/open" ) );

        //phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage
        return $body . "<img src='{$src}'/>";
    }

    protected function bind_click_tracker( string $body, stdClass $contact ) {
        $campaign = $this->vend_task['campaign'];

        if ( 0 == $campaign->tracking_link_click ) {
            return $body;
        }

        $click_tracker_link = get_rest_url( null, "vendtics/campaigns/email/link" );
    
        return preg_replace_callback(
            vendtics_anchor_url_regex(), function ( $matches ) use ( $contact, $campaign, $click_tracker_link ) {
                $original_url = $matches[1];
    
                $updated_url = add_query_arg(
                    [
                        'token'        => vendtics_generate_jwt_token( ["contact_id" => $contact->id, 'campaign_id' => $campaign->id] ),
                        'redirect_url' => $original_url,
                    ], $click_tracker_link 
                );
    
                // Return the updated <a> tag
                return str_replace( $original_url, $updated_url, $matches[0] );
            },
            $body
        );
    }

    protected function complete_campaign( stdClass $campaign ) {
        vendtics_campaign_repository()->mark_as_completed( $campaign->id );
    }

    protected function paused_campaign( stdClass $campaign ) {
        vendtics_campaign_repository()->mark_as_paused( $campaign->id );
    }

    /**
     * Extracts the WordPress plugin or theme directory name from a given file path.
     *
     * @param string $file_path The file path to search.
     * @return array|null An associative array with 'type' and 'name' if found, null otherwise.
     */
    function get_wp_directory_info( $file_path ) {
        // Regex pattern to match either a plugin or theme directory name
        $pattern = '/\/wp-content\/(plugins|themes)\/([^\/]+)\//';

        // Perform the regex match
        if ( preg_match( $pattern, $file_path, $matches ) ) {
            return [
                'type' => ucfirst( $matches[1] ), // "Plugins" or "Themes"
                'name' => $matches[2],           // The directory name
            ];
        }

        // Return null if no match is found
        return null;
    }
}