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

class VMO_Approval_Guard {
    private static $instance = null;
    private $wpdb;
    private $table_name;

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

        return self::$instance;
    }

    private function __construct() {
        global $wpdb;

        $this->wpdb = $wpdb;
        $this->table_name = $wpdb->prefix . 'vmo_action_queue';

        add_action('init', array($this, 'ensure_schema'), 6);
    }

    public function ensure_schema() {
        if (!function_exists('dbDelta')) {
            require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        }

        $charset_collate = $this->wpdb->get_charset_collate();
        $sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
            id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
            user_id BIGINT UNSIGNED NOT NULL,
            session_id VARCHAR(255) NOT NULL,
            action_type VARCHAR(80) NOT NULL,
            title VARCHAR(255) DEFAULT NULL,
            related_object_id VARCHAR(191) DEFAULT NULL,
            approval_required TINYINT(1) DEFAULT 1,
            status VARCHAR(40) DEFAULT 'pending',
            payload LONGTEXT NULL,
            approval_queue_id BIGINT UNSIGNED DEFAULT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY idx_user_id (user_id),
            KEY idx_session_id (session_id),
            KEY idx_action_type (action_type),
            KEY idx_status (status)
        ) {$charset_collate};";

        dbDelta($sql);
    }

    public function action_requires_approval($action_type) {
        return in_array((string) $action_type, array(
            'publish_website',
            'publish_major_update',
            'live_legal_injection',
            'campaign_launch',
            'outbound_communication',
            'price_change',
            'major_workflow_change',
            'external_provisioning',
        ), true);
    }

    public function queue_action($user_id, $session_id, $action_type, array $payload = array(), array $options = array()) {
        $user_id = (int) $user_id;
        $session_id = (string) $session_id;
        $action_type = (string) $action_type;
        $related_object_id = isset($options['related_object_id']) ? (string) $options['related_object_id'] : '';

        if ($user_id <= 0 || $session_id === '' || $action_type === '') {
            return 0;
        }

        $existing = $this->find_latest_action($user_id, $session_id, $action_type, $related_object_id, array('pending', 'approved'));
        if (!empty($existing['id'])) {
            return (int) $existing['id'];
        }

        $approval_queue_id = 0;
        if (function_exists('vmo_queue_add')) {
            $queue_result = vmo_queue_add(
                'other',
                $payload,
                $options['title'] ?? $this->default_title($action_type),
                isset($options['related_post_id']) ? (int) $options['related_post_id'] : null,
                $options['notes'] ?? null
            );
            if (!is_wp_error($queue_result)) {
                $approval_queue_id = (int) $queue_result;
            }
        }

        $this->wpdb->insert(
            $this->table_name,
            array(
                'user_id' => $user_id,
                'session_id' => $session_id,
                'action_type' => $action_type,
                'title' => $options['title'] ?? $this->default_title($action_type),
                'related_object_id' => $related_object_id,
                'approval_required' => $this->action_requires_approval($action_type) ? 1 : 0,
                'status' => 'pending',
                'payload' => wp_json_encode($payload),
                'approval_queue_id' => $approval_queue_id ?: null,
                'created_at' => current_time('mysql'),
                'updated_at' => current_time('mysql'),
            ),
            array('%d', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%d', '%s', '%s')
        );

        return (int) $this->wpdb->insert_id;
    }

    public function can_execute($action_type, $user_id, $session_id, array $website_payload = array(), array $business_package = array(), array $context = array()) {
        $user_id = (int) $user_id;
        $session_id = (string) $session_id;
        $requires_approval = $this->action_requires_approval($action_type);
        $related_object_id = isset($context['related_object_id']) ? (string) $context['related_object_id'] : '';
        $readiness = ($action_type === 'publish_website')
            ? $this->evaluate_publish_readiness($user_id, $session_id, $website_payload, $business_package, $context)
            : array('publish_ready' => true, 'checklist' => array());

        $queue_id = $this->queue_action($user_id, $session_id, $action_type, array(
            'readiness' => $readiness,
            'business_package_keys' => array_keys($business_package),
        ), array(
            'related_object_id' => $related_object_id,
            'related_post_id' => isset($context['related_post_id']) ? (int) $context['related_post_id'] : 0,
            'title' => $context['title'] ?? $this->default_title($action_type),
            'notes' => $readiness['summary'] ?? null,
        ));

        $approval_granted = !$requires_approval || !empty($context['user_requested_publish']) || !empty($context['user_requested_approval']);
        if ($approval_granted && $queue_id > 0) {
            $this->mark_action_status($queue_id, 'approved');
        }

        $allowed = !empty($readiness['publish_ready']) && $approval_granted;
        if ($allowed && $queue_id > 0) {
            $this->mark_action_status($queue_id, 'executed');
        }

        return array(
            'allowed' => $allowed,
            'approval_required' => $requires_approval,
            'approval_granted' => $approval_granted,
            'queue_id' => $queue_id,
            'readiness' => $readiness,
            'message' => $allowed
                ? 'Publish approval granted and readiness checks passed.'
                : $this->build_block_message($requires_approval, $approval_granted, $readiness),
        );
    }

    public function evaluate_publish_readiness($user_id, $session_id, array $website_payload = array(), array $business_package = array(), array $context = array()) {
        $brief_bundle = function_exists('vmo_get_master_business_brief_service')
            ? vmo_get_master_business_brief_service()->get_active_brief($session_id, $user_id)
            : array();
        $brief_locked = !empty($brief_bundle) && (($brief_bundle['status'] ?? 'draft') !== 'draft');

        $qa_report = !empty($context['qa_report']) && is_array($context['qa_report'])
            ? $context['qa_report']
            : array();
        if (empty($qa_report) && function_exists('vmo_get_website_qa_service')) {
            $qa_context = array(
                'draft_key' => $context['draft_key'] ?? ($context['related_object_id'] ?? ''),
                'related_post_id' => isset($context['related_post_id']) ? (int) $context['related_post_id'] : 0,
            );
            $qa_report = vmo_get_website_qa_service()->run_qa($user_id, $session_id, $website_payload, $business_package, $qa_context);
        }

        if (!empty($website_payload) && function_exists('vmo_get_website_final_qa_gate')) {
            $qa_context = is_array($context['qa_context'] ?? null) ? $context['qa_context'] : array();
            $qa_context['draft_key'] = $qa_context['draft_key'] ?? ($context['draft_key'] ?? ($context['related_object_id'] ?? ''));
            $qa_context['related_post_id'] = $qa_context['related_post_id'] ?? (isset($context['related_post_id']) ? (int) $context['related_post_id'] : 0);
            if (is_array($context['canonical_generation_context'] ?? null)) {
                $qa_context['canonical_generation_context'] = $context['canonical_generation_context'];
            }
            if (!empty($context['visual_preset'])) {
                $qa_context['visual_preset'] = $context['visual_preset'];
            }
            $final_qa_gate = vmo_get_website_final_qa_gate()->evaluate($user_id, $session_id, $website_payload, $business_package, $qa_context);
            $qa_report = vmo_get_website_final_qa_gate()->merge_with_existing_report($qa_report, $final_qa_gate);
        }

        $checklist = array(
            'business_brief_locked' => $brief_locked,
            'website_qa_passed' => !empty($qa_report['publish_ready']),
            'final_qa_passed' => !isset($qa_report['checklist']['final_qa_passed']) || !empty($qa_report['checklist']['final_qa_passed']),
            'required_legal_pages_present' => !empty($qa_report['checklist']['required_legal_pages_present']),
            'media_complete' => !empty($qa_report['checklist']['media_complete']),
        );

        return array(
            'publish_ready' => !in_array(false, $checklist, true),
            'checklist' => $checklist,
            'qa_report' => $qa_report,
            'summary' => !empty($qa_report['summary'])
                ? $qa_report['summary']
                : 'Publish readiness was evaluated against the business brief, QA checks, legal coverage, and media completion.',
        );
    }

    public function mark_action_status($queue_id, $status) {
        $queue_id = (int) $queue_id;
        if ($queue_id <= 0) {
            return false;
        }

        return false !== $this->wpdb->update(
            $this->table_name,
            array(
                'status' => sanitize_key($status),
                'updated_at' => current_time('mysql'),
            ),
            array('id' => $queue_id),
            array('%s', '%s'),
            array('%d')
        );
    }

    public function find_latest_action($user_id, $session_id, $action_type, $related_object_id = '', $statuses = array()) {
        $user_id = (int) $user_id;
        $session_id = (string) $session_id;
        $action_type = (string) $action_type;
        $related_object_id = (string) $related_object_id;
        if ($user_id <= 0 || $session_id === '' || $action_type === '') {
            return array();
        }

        $sql = "SELECT * FROM {$this->table_name} WHERE user_id = %d AND session_id = %s AND action_type = %s";
        $params = array($user_id, $session_id, $action_type);

        if ($related_object_id !== '') {
            $sql .= ' AND related_object_id = %s';
            $params[] = $related_object_id;
        }
        if (!empty($statuses)) {
            $statuses = array_values(array_filter(array_map('sanitize_key', $statuses)));
            if (!empty($statuses)) {
                $placeholders = implode(', ', array_fill(0, count($statuses), '%s'));
                $sql .= " AND status IN ({$placeholders})";
                $params = array_merge($params, $statuses);
            }
        }

        $sql .= ' ORDER BY id DESC LIMIT 1';

        $row = $this->wpdb->get_row($this->wpdb->prepare($sql, $params), ARRAY_A);
        return $row ? $row : array();
    }

    private function default_title($action_type) {
        if ($action_type === 'publish_website') {
            return 'Review website draft for publication';
        }

        return ucwords(str_replace('_', ' ', (string) $action_type));
    }

    private function build_block_message($requires_approval, $approval_granted, array $readiness) {
        if (!$requires_approval) {
            return 'This action cannot run because readiness checks failed.';
        }
        if (!$approval_granted) {
            return 'This action requires explicit user approval before execution.';
        }

        $failures = array();
        foreach (($readiness['checklist'] ?? array()) as $key => $passed) {
            if (!$passed) {
                $failures[] = str_replace('_', ' ', $key);
            }
        }

        if (empty($failures)) {
            return 'This action is pending approval queue processing.';
        }

        return 'Publish is blocked until these items pass: ' . implode(', ', $failures) . '.';
    }
}

if (!function_exists('vmo_get_approval_guard')) {
    function vmo_get_approval_guard() {
        return VMO_Approval_Guard::get_instance();
    }
}
