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

class VMO_Promotion_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_jobs', array($this, 'run_due_jobs'));
    }

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

        $jobs = $this->store->get_due_jobs((int) $limit);
        $summary = array(
            'processed' => 0,
            'published' => 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 job record.';
                $summary['jobs'][] = $job_result;
                continue;
            }

            $this->store->mark_job_processing($job_id);

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

            if (!$connector || empty($content_item)) {
                $job_result['message'] = 'Missing connector or content item.';
                $this->store->mark_job_result($job_id, array(
                    'publish_status' => 'blocked',
                    'last_error_code' => 'missing_dependencies',
                    'last_error_message' => $job_result['message'],
                    'provider_response_json' => array(),
                ));
                $summary['blocked']++;
                $summary['jobs'][] = $job_result;
                continue;
            }

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

            $has_media = !empty($content_item['media_bundle']['manual_assets']) || !empty($content_item['media_bundle_id']);
            $response = $has_media ? $connector->publish_media_post($publish_input) : $connector->publish_text_post($publish_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_job_result($job_id, array(
                    'publish_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_job_blocked' : 'promotion_job_failed',
                    sprintf('Promotion job %d for %s did not publish.', $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_post_id = sanitize_text_field($response['provider_post_id'] ?? '');
            $message = sanitize_text_field($response['message'] ?? 'Published');
            $this->store->mark_job_result($job_id, array(
                'publish_status' => 'published',
                'provider_post_id' => $provider_post_id,
                'provider_response_json' => $response,
                'published_at' => current_time('mysql'),
                'last_error_code' => '',
                'last_error_message' => '',
            ));
            $this->store->log_event(
                (int) ($job['user_id'] ?? 0),
                'promotion_job_published',
                sprintf('Promotion job %d published to %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_post_id' => $provider_post_id,
                    'response' => $response,
                )
            );

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

        return $summary;
    }
}
