<?php
if (!defined('ABSPATH')) {
    exit;
}

class VMO_Promotion_Ad_Execution_Engine {
    private static $instance = null;
    private $store;
    private $registry;

    public static function get_instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    private function __construct() {
        $this->store = class_exists('VMO_Promotion_Data_Store') ? VMO_Promotion_Data_Store::get_instance() : null;
        $this->registry = class_exists('VMO_Promotion_Provider_Registry') ? VMO_Promotion_Provider_Registry::get_instance() : null;
        add_action('vmo_promotion_run_due_ad_jobs', array($this, 'run_due_jobs'));
    }

    public function run_due_jobs($limit = 10) {
        if (!$this->store || !$this->registry) {
            return array(
                'processed' => 0,
                'launched' => 0,
                'blocked' => 0,
                'failed' => 0,
                'jobs' => array(),
            );
        }

        $jobs = $this->store->get_due_ad_jobs((int) $limit);
        $summary = array(
            'processed' => 0,
            'launched' => 0,
            'blocked' => 0,
            'failed' => 0,
            'jobs' => array(),
        );

        foreach ($jobs as $job) {
            $summary['processed']++;
            $job_id = (int) ($job['id'] ?? 0);
            $job_result = array(
                'job_id' => $job_id,
                'platform_key' => sanitize_key($job['platform_key'] ?? ''),
                'status' => 'blocked',
                'message' => '',
            );

            if ($job_id <= 0) {
                $summary['blocked']++;
                $job_result['message'] = 'Invalid ad job record.';
                $summary['jobs'][] = $job_result;
                continue;
            }

            $this->store->mark_ad_job_processing($job_id);
            $connector = $this->registry->get_connector($job['platform_key'] ?? '');
            $account = $this->store->get_connected_account_by_id((int) ($job['connected_account_id'] ?? 0));

            if (!$connector) {
                $job_result['message'] = 'Missing ads connector.';
                $this->store->mark_ad_job_result($job_id, array(
                    'job_status' => 'blocked',
                    'last_error_code' => 'missing_connector',
                    'last_error_message' => $job_result['message'],
                    'provider_response_json' => array(),
                ));
                $summary['blocked']++;
                $summary['jobs'][] = $job_result;
                continue;
            }

            $launch_input = array(
                'ad_job' => $job,
                'connected_account' => $account,
                'user_id' => (int) ($job['user_id'] ?? 0),
            );

            $response = $connector->launch_ad_campaign($launch_input);
            if (is_wp_error($response)) {
                $code = sanitize_key($response->get_error_code());
                $message = $response->get_error_message();
                $blocked = in_array($code, array('connector_not_implemented', 'provider_not_ready', 'missing_credentials'), true);

                $this->store->mark_ad_job_result($job_id, array(
                    'job_status' => $blocked ? 'blocked' : 'failed',
                    'last_error_code' => $code,
                    'last_error_message' => $message,
                    'provider_response_json' => $response->get_error_data(),
                ));
                $this->store->log_event(
                    (int) ($job['user_id'] ?? 0),
                    $blocked ? 'promotion_ad_job_blocked' : 'promotion_ad_job_failed',
                    sprintf('Ad job %d for %s did not launch.', $job_id, sanitize_text_field($job['platform_label'] ?? $job['platform_key'] ?? 'provider')),
                    array(
                        'job_id' => $job_id,
                        'platform_key' => sanitize_key($job['platform_key'] ?? ''),
                        'error_code' => $code,
                        'error_message' => $message,
                    )
                );

                if ($blocked) {
                    $summary['blocked']++;
                    $job_result['status'] = 'blocked';
                } else {
                    $summary['failed']++;
                    $job_result['status'] = 'failed';
                }

                $job_result['message'] = $message;
                $summary['jobs'][] = $job_result;
                continue;
            }

            $provider_campaign_id = sanitize_text_field($response['provider_campaign_id'] ?? '');
            $message = sanitize_text_field($response['message'] ?? 'Ad campaign launched');
            $this->store->mark_ad_job_result($job_id, array(
                'job_status' => 'launched',
                'provider_campaign_id' => $provider_campaign_id,
                'provider_response_json' => $response,
                'launched_at' => current_time('mysql'),
                'last_error_code' => '',
                'last_error_message' => '',
            ));
            $this->store->log_event(
                (int) ($job['user_id'] ?? 0),
                'promotion_ad_job_launched',
                sprintf('Ad job %d launched for %s.', $job_id, sanitize_text_field($job['platform_label'] ?? $job['platform_key'] ?? 'provider')),
                array(
                    'job_id' => $job_id,
                    'platform_key' => sanitize_key($job['platform_key'] ?? ''),
                    'provider_campaign_id' => $provider_campaign_id,
                    'response' => $response,
                )
            );

            $summary['launched']++;
            $job_result['status'] = 'launched';
            $job_result['message'] = $message;
            $summary['jobs'][] = $job_result;
        }

        return $summary;
    }
}
