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

class VMO_Consultation_Deliverables_Gate {
    private static $instance = null;

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

    public function evaluate($user_id, $session_id, array $consultation_data = array()) {
        $user_id = (int) $user_id;
        $session_id = sanitize_text_field((string) $session_id);
        $context = $this->hydrate_context($user_id, $session_id, $consultation_data);

        $checks = array(
            'website_ready' => $this->evaluate_website($user_id, $session_id, $context),
            'emails_ready' => $this->evaluate_email($user_id, $session_id, $context),
            'phone_ready' => $this->evaluate_phone($user_id, $session_id, $context),
            'forms_ready' => $this->evaluate_forms($user_id, $session_id, $context),
            'payments_ready_if_needed' => $this->evaluate_payments($user_id, $session_id, $context),
            'products_ready_if_needed' => $this->evaluate_products($user_id, $session_id, $context),
            'documents_ready' => $this->evaluate_documents($user_id, $session_id, $context),
            'leads_ready' => $this->evaluate_leads($user_id, $session_id, $context),
            'kpis_ready' => $this->evaluate_kpis($user_id, $session_id, $context),
            'today_tab_ready' => $this->evaluate_today($user_id, $session_id, $context),
            'dashboard_tools_ready' => $this->evaluate_dashboard($user_id, $session_id, $context),
            'launch_tour_ready' => $this->evaluate_launch_tour($user_id, $session_id, $context),
        );

        $missing = array();
        foreach ($checks as $key => $check) {
            if (empty($check['ready'])) {
                $resolution = $this->build_resolution_step($key, $check, $context);
                $missing[] = array(
                    'key' => $key,
                    'label' => $check['label'] ?? ucwords(str_replace('_', ' ', $key)),
                    'reason' => $check['reason'] ?? 'Not ready',
                    'resolution' => $resolution,
                    'details' => $check['details'] ?? array(),
                );
            }
        }

        $recovery_plan = $this->build_recovery_plan($missing);

        $result = array(
            'status' => empty($missing) ? 'ready' : 'needs_attention',
            'launch_ready' => empty($missing),
            'missing_items' => $missing,
            'recovery_plan' => $recovery_plan,
            'can_continue_consultation' => true,
            'checks' => $checks,
            'evaluated_at' => current_time('mysql'),
            'session_id' => $session_id,
            'user_id' => $user_id,
        );

        update_user_meta($user_id, 'vmo_phase8_deliverables_gate_' . $session_id, $result);
        update_user_meta($user_id, 'vmo_phase8_deliverables_gate_latest', $result);

        return $result;
    }

    private function build_recovery_plan(array $missing) {
        if (empty($missing)) {
            return array(
                'status' => 'complete',
                'next_item' => null,
                'steps' => array(),
                'message' => 'All launch deliverables are verified.',
            );
        }

        $steps = array();
        foreach ($missing as $item) {
            if (!is_array($item)) {
                continue;
            }
            $steps[] = array(
                'key' => sanitize_key((string) ($item['key'] ?? '')),
                'label' => sanitize_text_field((string) ($item['label'] ?? 'Missing launch item')),
                'reason' => sanitize_text_field((string) ($item['reason'] ?? 'Not ready')),
                'resolution' => is_array($item['resolution'] ?? null) ? $item['resolution'] : array(),
            );
        }

        return array(
            'status' => 'needs_attention',
            'next_item' => $steps[0] ?? null,
            'steps' => $steps,
            'message' => 'The consultation can continue. Resolve these launch items one at a time, then re-run the final deliverables gate.',
        );
    }

    private function build_resolution_step($key, array $check, array $context) {
        $defaults = array(
            'owner' => 'jerreme_ai_and_user',
            'action' => 'Review this item, collect the missing information, and re-run the final deliverables gate.',
            'question' => 'Can you confirm the missing details for this launch item?',
            'success_condition' => 'The gate check returns ready.',
            'dashboard_area' => 'Business dashboard',
        );

        $map = array(
            'website_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Generate or refresh the consultation website preview, verify page count, media, forms, and preview URL, then save the website result to the session.',
                'question' => 'I still need to finish the website preview. Should I regenerate the website package now using the consultation details we already collected?',
                'success_condition' => 'A generated website preview or post exists with at least one page and draft/preview readiness.',
                'dashboard_area' => 'Website / Builder',
            ),
            'emails_ready' => array(
                'owner' => 'jerreme_ai_and_user',
                'action' => 'Confirm mailbox roles, create or verify VMO email accounts, enable auto-reply, and confirm DNS/Zoho or existing mailbox routing.',
                'question' => 'Which email setup should I complete: VMO auto-provisioning, Zoho/manual DNS, or existing business inboxes?',
                'success_condition' => 'Role mailboxes, VMO Email UI, form routing, auto-reply, and DNS/provider status are verified.',
                'dashboard_area' => 'VMO Email',
            ),
            'phone_ready' => array(
                'owner' => 'jerreme_ai_and_user',
                'action' => 'Provision or verify the business number, inbound/outbound calling, extensions, AI agent, website placement, and dashboard logging.',
                'question' => 'Do you want me to continue with phone provisioning now, or are you bringing an existing business number?',
                'success_condition' => 'Number, inbound, outbound, extensions, AI agent, website integration, and dashboard integration are all ready.',
                'dashboard_area' => 'Phone / SMS',
            ),
            'forms_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Map each generated website form to the correct VMO mailbox and confirm the routing contract.',
                'question' => 'Which mailbox should receive website form submissions if you want to override the default info/support routing?',
                'success_condition' => 'Website forms are connected to verified mailboxes.',
                'dashboard_area' => 'Website Forms / VMO Email',
            ),
            'payments_ready_if_needed' => array(
                'owner' => 'user_human_action_then_jerreme_ai',
                'action' => 'Guide the user through VMO Pay setup, then verify account status, checkout runtime, buy buttons, webhook-to-business-flow bridge, fulfillment queue, completion action, buyer receipts, owner notifications, order ledger, CRM history, and CFO reporting.',
                'question' => 'Will this business accept payments online? If yes, I will walk you through VMO Pay setup and verify checkout afterward.',
                'success_condition' => 'Payment account, checkout, buy buttons, webhook, business-flow fulfillment record, dashboard completion action, receipts, owner notifications, order ledger, CRM update, and CFO dashboard reporting are verified when payments are required.',
                'dashboard_area' => 'VMO Pay / Orders',
            ),
            'products_ready_if_needed' => array(
                'owner' => 'jerreme_ai_and_user',
                'action' => 'Collect or confirm product/service names, descriptions, prices, variations, images/videos, fulfillment, and demo/live status.',
                'question' => 'Let us finish your catalog. What is the first product or service name, price, description, and any image/video you want used?',
                'success_condition' => 'At least one live priced catalog item exists in the VMO store table when catalog or checkout output is required.',
                'dashboard_area' => 'Products / Services',
            ),
            'documents_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Generate or refresh all required business, marketing, SEO, legal, catalog, lead, website, phone/email, and campaign documents.',
                'question' => 'I can regenerate the missing launch documents now. Do you want the standard document set, or should any policy use special terms?',
                'success_condition' => 'Every required launch document type is stored.',
                'dashboard_area' => 'Documents',
            ),
            'leads_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Run real AI lead discovery and save only verified non-template leads with primary, secondary, and tertiary source tiers.',
                'question' => 'I need to run real lead discovery. Which market should I prioritize first: local, national, online, or a specific city/region?',
                'success_condition' => 'The CRM contains at least one verified non-template lead.',
                'dashboard_area' => 'CRM / Leads',
            ),
            'kpis_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Create KPI targets with current value, target value, gap, and recommended action from the business manifest.',
                'question' => 'I will set your first KPI targets from the consultation. Are revenue, leads, calls, and traffic the right starting metrics?',
                'success_condition' => 'KPI targets are stored for dashboard tracking.',
                'dashboard_area' => 'KPI Dashboard',
            ),
            'today_tab_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Populate Today with launch actions and daily activities from the roadmap.',
                'question' => 'I can create your first Today actions now from the launch roadmap. Should I prioritize sales, operations, or compliance first?',
                'success_condition' => 'Today has pending launch tasks or daily activities.',
                'dashboard_area' => 'Today',
            ),
            'dashboard_tools_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Regenerate the business manifest and operating state so dashboard modules know the business condition.',
                'question' => 'I need to refresh the dashboard operating state. Should I use the latest consultation answers as the source of truth?',
                'success_condition' => 'Manifest, operating state, KPI contracts, and dashboard class readiness are present.',
                'dashboard_area' => 'Strategic Dashboard',
            ),
            'launch_tour_ready' => array(
                'owner' => 'jerreme_ai',
                'action' => 'Generate and save the final VMO launch tour script and audio after the deliverables gate has enough context.',
                'question' => 'I need to generate your final website and dashboard walkthrough audio. Should I create the launch tour now?',
                'success_condition' => 'Launch tour script and audio URL are stored for the session.',
                'dashboard_area' => 'Consultation / Launch Tour',
            ),
        );

        return array_merge($defaults, $map[$key] ?? array());
    }

    public function required_document_types(array $context = array()) {
        $required = array(
            'privacy_policy',
            'terms_of_service',
            'sms_policy',
            'email_policy',
            'refund_policy',
            'business_plan',
            'marketing_plan',
            'seo_plan',
            'competitor_analysis',
            'brand_guidelines',
            'product_catalog',
            'service_catalog',
            'lead_report',
            'website_strategy',
            'phone_email_setup_guide',
            'campaign_plan',
        );

        if ($this->needs_shipping_policy($context)) {
            $required[] = 'shipping_policy';
        }

        return array_values(array_unique($required));
    }

    private function hydrate_context($user_id, $session_id, array $consultation_data) {
        $context = $consultation_data;
        $row = $this->get_consultation_row($session_id);

        if ($row) {
            $row_data = $this->decode_maybe_json($row->consultation_data ?? '');
            if (is_array($row_data)) {
                $context = array_replace_recursive($row_data, $context);
            }
            $website_data = $this->decode_maybe_json($row->website_data ?? '');
            if (is_array($website_data)) {
                $context['website_data'] = $website_data;
            }
        }

        $operating_state = get_user_meta($user_id, 'vmo_business_operating_state_' . $session_id, true);
        if (!is_array($operating_state)) {
            $operating_state = get_user_meta($user_id, 'vmo_business_operating_state', true);
        }
        $context['operating_state'] = is_array($operating_state) ? $operating_state : array();

        $manifest = get_user_meta($user_id, 'vmo_business_manifest_' . $session_id, true);
        if (!is_array($manifest)) {
            $manifest = get_user_meta($user_id, 'vmo_business_manifest', true);
        }
        $context['business_manifest'] = is_array($manifest) ? $manifest : array();

        return $context;
    }

    private function get_consultation_row($session_id) {
        global $wpdb;
        if (empty($session_id)) {
            return null;
        }
        $table = $wpdb->prefix . 'vmo_consultations';
        if (!$this->table_exists($table)) {
            return null;
        }
        return $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE session_id = %s LIMIT 1", $session_id));
    }

    private function evaluate_website($user_id, $session_id, array $context) {
        $state = $this->array_path($context, array('operating_state', 'website'), array());
        $website_data = $this->array_path($context, array('website_data', 'website'), array());
        if (empty($website_data) && !empty($context['website_data']) && is_array($context['website_data'])) {
            $website_data = $context['website_data'];
        }

        $pages_count = (int) ($state['pages_count'] ?? 0);
        if ($pages_count <= 0 && !empty($website_data['pages_created']) && is_array($website_data['pages_created'])) {
            $pages_count = count($website_data['pages_created']);
        }
        if ($pages_count <= 0 && !empty($website_data['pages_map']) && is_array($website_data['pages_map'])) {
            $pages_count = count($website_data['pages_map']);
        }

        $approved_count = $this->approved_pages_count($context, $state, $website_data);
        $page_count_ready = $approved_count <= 0 ? $pages_count > 0 : $pages_count >= $approved_count;
        $media_complete = !empty($state['media_complete']) || !empty($website_data['media_complete']);
        $preview_ready = !empty($state['preview_ready']) || !empty($website_data['preview_ready']);
        $draft_ready = !empty($state['draft_ready']) || !empty($website_data['draft_ready']);
        $ready = $page_count_ready && $media_complete && $preview_ready && $draft_ready && (!empty($website_data['preview_url']) || !empty($state['preview_url']));

        return array(
            'label' => 'Generated website',
            'ready' => $ready,
            'reason' => $ready ? 'Website page count, media, draft, and preview readiness are verified.' : 'Website readiness requires generated pages to meet approved architecture count, media_complete, preview_ready, draft_ready, and a preview URL.',
            'details' => array('pages_count' => $pages_count, 'approved_pages_count' => $approved_count, 'media_complete' => $media_complete, 'preview_ready' => $preview_ready, 'draft_ready' => $draft_ready),
        );
    }

    private function evaluate_email($user_id, $session_id, array $context) {
        $snapshot = get_user_meta($user_id, 'vmo_final_email_readiness_' . $session_id, true);
        if (is_array($snapshot) && isset($snapshot['email_accounts_created'])) {
            $ready = !empty($snapshot['email_accounts_created'])
                && !empty($snapshot['email_roles_confirmed'])
                && !empty($snapshot['mailbox_ui_ready'])
                && !empty($snapshot['forms_routed_to_mailboxes'])
                && !empty($snapshot['auto_reply_enabled'])
                && !empty($snapshot['dns_or_zoho_status_confirmed'])
                && !empty($snapshot['smtp_verified'])
                && !empty($snapshot['imap_verified']);
            return array(
                'label' => 'VMO email system',
                'ready' => $ready,
                'reason' => $ready ? 'Mailboxes, routing, auto-reply, UI, DNS/provider, SMTP, and IMAP are verified.' : 'Email accounts, routing, auto-reply, UI, DNS/provider, SMTP, or IMAP verification is incomplete.',
                'details' => $snapshot,
            );
        }

        return array(
            'label' => 'VMO email system',
            'ready' => false,
            'reason' => 'Final email readiness snapshot is missing. Phase 8 must verify accounts, roles, UI, routing, auto-reply, DNS/provider, SMTP, and IMAP.',
            'details' => array('snapshot_required' => true),
        );
    }

    private function evaluate_phone($user_id, $session_id, array $context) {
        $snapshot = get_user_meta($user_id, 'vmo_final_phone_readiness_' . $session_id, true);
        if (is_array($snapshot) && isset($snapshot['number_provisioned'])) {
            $ready = !empty($snapshot['number_provisioned'])
                && !empty($snapshot['inbound_ready'])
                && !empty($snapshot['outbound_ready'])
                && !empty($snapshot['extensions_ready'])
                && !empty($snapshot['ai_agent_ready'])
                && !empty($snapshot['website_integrated'])
                && !empty($snapshot['dashboard_integrated']);
            return array(
                'label' => 'Phone and SMS system',
                'ready' => $ready,
                'reason' => $ready ? 'Phone number, routing, AI agent, website, and dashboard integrations are verified.' : 'Phone number, routing, AI agent, website, or dashboard integration is incomplete.',
                'details' => $snapshot,
            );
        }

        return array(
            'label' => 'Phone and SMS system',
            'ready' => false,
            'reason' => 'Final phone readiness snapshot is missing. Phase 8 must verify number, inbound, outbound, extensions, AI agent, website, and dashboard integration.',
            'details' => array('snapshot_required' => true),
        );
    }

    private function evaluate_forms($user_id, $session_id, array $context) {
        $email = $this->evaluate_email($user_id, $session_id, $context);
        $website = $this->evaluate_website($user_id, $session_id, $context);
        $manifest_forms = $this->array_path($context, array('business_manifest', 'contracts', 'forms'), array());
        $forms_routed = !empty($email['ready']) && (!empty($email['details']['forms_routed_to_mailboxes']) || !empty($manifest_forms));

        return array(
            'label' => 'Website forms and routing',
            'ready' => !empty($website['ready']) && $forms_routed,
            'reason' => (!empty($website['ready']) && $forms_routed) ? 'Forms are mapped to verified mailboxes.' : 'Website forms are not yet verified against a ready VMO mailbox route.',
            'details' => array('forms_contracts' => $manifest_forms, 'email_ready' => !empty($email['ready'])),
        );
    }

    private function evaluate_payments($user_id, $session_id, array $context) {
        $needed = $this->payments_required($context);
        if (!$needed) {
            return array('label' => 'Payments', 'ready' => true, 'reason' => 'No payment collection requirement detected.', 'details' => array('required' => false));
        }

        $snapshot = get_user_meta($user_id, 'vmo_final_payment_readiness_' . $session_id, true);
        if (is_array($snapshot) && isset($snapshot['payment_account_ready'])) {
            $ready = !empty($snapshot['payment_account_ready'])
                && ($snapshot['payment_onboarding_status'] ?? '') === 'verified_ready'
                && !empty($snapshot['checkout_ready'])
                && !empty($snapshot['buy_buttons_valid'])
                && !empty($snapshot['webhook_secret_configured'])
                && !empty($snapshot['webhook_handler_ready'])
                && !empty($snapshot['receipt_pipeline_ready'])
                && !empty($snapshot['owner_notification_ready'])
                && !empty($snapshot['cfo_ledger_ready'])
                && !empty($snapshot['order_dashboard_ready'])
                && !empty($snapshot['full_commerce_chain_ready']);
            return array(
                'label' => 'Payments and checkout',
                'ready' => $ready,
                'reason' => $ready ? 'Payment onboarding, checkout, buy buttons, webhook, receipts, owner notifications, order ledger, and CFO reporting are verified.' : 'Payment onboarding, checkout, buy buttons, webhook, receipts, owner notifications, order ledger, or CFO reporting is incomplete.',
                'details' => $snapshot,
            );
        }

        return array(
            'label' => 'Payments and checkout',
            'ready' => false,
            'reason' => 'Final payment readiness snapshot is missing. Payment-required launches must complete and verify VMO Pay onboarding before launch.',
            'details' => array('required' => true, 'snapshot_required' => true),
        );
    }

    private function evaluate_products($user_id, $session_id, array $context) {
        $needed = $this->catalog_required($context);
        if (!$needed) {
            return array('label' => 'Products and catalog', 'ready' => true, 'reason' => 'No product catalog requirement detected.', 'details' => array('required' => false));
        }

        $products = $this->array_path($context, array('extracted_information', 'products_inventory'), array());
        $services = $this->array_path($context, array('extracted_information', 'services_inventory'), array());
        $payment_products = $this->array_path($context, array('operating_state', 'systems', 'payments', 'products_count'), 0);
        $store_products = $this->active_store_product_count($user_id, $session_id);
        $count = count(is_array($products) ? $products : array()) + count(is_array($services) ? $services : array());
        $count = max($count, (int) $payment_products, $store_products);
        $has_demo = $this->array_has_demo_items($products) || $this->array_has_demo_items($services);
        $packet_gate = $this->product_packet_gate_from_context($context);
        $packets_ready = empty($packet_gate['required']) || !empty($packet_gate['ready']);
        $catalog_packet_gate = $this->validate_catalog_packets($products, $services, $context);
        $ready = $count > 0 && $store_products > 0 && !$has_demo && $packets_ready && !empty($catalog_packet_gate['ready']);

        return array(
            'label' => 'Products and catalog',
            'ready' => $ready,
            'reason' => $ready ? 'Live priced catalog items and complete product content/media packets are ready.' : 'Live priced product/service catalog items are missing, not stored for checkout, marked as demo, or missing required product content/media packets.',
            'details' => array('required' => true, 'catalog_count' => $count, 'store_products_count' => $store_products, 'has_demo_items' => $has_demo, 'product_packet_gate' => $packet_gate, 'catalog_packet_gate' => $catalog_packet_gate),
        );
    }

    private function validate_catalog_packets($products, $services, array $context) {
        $product_items = is_array($products) ? $products : array();
        $service_items = is_array($services) ? $services : array();
        $items = array_merge($product_items, $service_items);
        $product_count = count($product_items);
        if (empty($items)) {
            return array('ready' => false, 'missing' => array(array('item' => 'catalog', 'fields' => array('product_name'))));
        }

        $missing = array();
        foreach ($items as $index => $item) {
            $is_service = $index >= $product_count;
            $item = is_array($item) ? $item : array('product_name' => (string) $item);
            $fields = array();
            $name = $item['product_name'] ?? $item['service_name'] ?? $item['name'] ?? $item['title'] ?? '';
            $description = $item['product_description'] ?? $item['service_description'] ?? $item['description'] ?? '';
            $price = $item['price'] ?? $item['price_cents'] ?? $item['amount'] ?? '';
            $currency = $item['currency'] ?? $this->array_path($context, array('currency'), '');
            $category = $item['category'] ?? $item['type'] ?? '';
            $has_media = !empty($item['image']) || !empty($item['image_url']) || !empty($item['main_image']) || !empty($item['images']) || !empty($item['media']) || !empty($item['image_generation_approval']) || !empty($item['images_or_image_generation_approval']);
            $has_shipping = array_key_exists('shipping_required', $item) || array_key_exists('shipping', $item) || array_key_exists('fulfillment_type', $item) || array_key_exists('delivery_method', $item);
            $has_inventory = array_key_exists('inventory', $item) || array_key_exists('inventory_count', $item) || !empty($item['unlimited_inventory']) || !empty($item['inventory_or_unlimited']);
            $refund_policy = $item['refund_policy'] ?? $this->array_path($context, array('refund_policy'), '');
            $checkout_label = $item['checkout_button_label'] ?? $this->array_path($context, array('checkout_button_label'), '');

            if (trim((string) $name) === '') $fields[] = 'product_name';
            if (trim((string) $description) === '') $fields[] = 'product_description';
            if (trim((string) $price) === '') $fields[] = 'price';
            if (trim((string) $currency) === '') $fields[] = 'currency';
            if (trim((string) $category) === '') $fields[] = 'category';
            if (!$has_media) $fields[] = 'images_or_image_generation_approval';
            if (!$is_service && !$has_shipping) $fields[] = 'shipping_required';
            if (!$is_service && !$has_inventory) $fields[] = 'inventory_or_unlimited';
            if (trim((string) $refund_policy) === '') $fields[] = 'refund_policy';
            if (trim((string) $checkout_label) === '') $fields[] = 'checkout_button_label';

            if (!empty($fields)) {
                $missing[] = array('item_index' => $index, 'item' => sanitize_text_field((string) ($name ?: 'Catalog item ' . ($index + 1))), 'fields' => $fields);
            }
        }

        return array('ready' => empty($missing), 'missing' => $missing);
    }

    private function product_packet_gate_from_context(array $context) {
        $summary = $this->array_path($context, array('business_manifest', 'ecommerce_config', 'product_generation_packets'), array());
        if (empty($summary)) {
            $summary = $this->array_path($context, array('operating_state', 'systems', 'ecommerce', 'product_generation_packets'), array());
        }
        if (empty($summary)) {
            $summary = $this->array_path($context, array('product_generation_packets'), array());
        }
        if (!is_array($summary) || empty($summary)) {
            return array('required' => false, 'ready' => true);
        }
        $required = !empty($summary['product_count']) || !empty($summary['required_content_fields']) || !empty($summary['required_media_slots']);
        return array(
            'required' => $required,
            'ready' => !$required || !empty($summary['ready_before_preview']),
            'content_packets_complete' => !$required || !empty($summary['content_packets_complete']),
            'media_packets_complete' => !$required || !empty($summary['media_packets_complete']),
            'product_count' => (int) ($summary['product_count'] ?? 0),
            'missing' => is_array($summary['missing'] ?? null) ? $summary['missing'] : array(),
        );
    }

    private function evaluate_documents($user_id, $session_id, array $context) {
        $required = $this->required_document_types($context);
        $available = $this->stored_document_types($user_id, $session_id);
        $missing = array_values(array_diff($required, $available));

        return array(
            'label' => 'Launch documents',
            'ready' => empty($missing),
            'reason' => empty($missing) ? 'All required launch documents are present.' : 'Required launch documents are missing: ' . implode(', ', $missing),
            'details' => array('required' => $required, 'available' => $available, 'missing' => $missing),
        );
    }

    private function evaluate_leads($user_id, $session_id, array $context) {
        global $wpdb;
        $table = $wpdb->prefix . 'vmo_contacts';
        if (!$this->table_exists($table)) {
            return array('label' => 'CRM leads', 'ready' => false, 'reason' => 'CRM contacts table is missing.', 'details' => array());
        }

        $session_clause = '';
        $session_args = array();
        if (!empty($session_id) && $this->column_exists($table, 'session_id')) {
            $session_clause = ' AND session_id = %s';
            $session_args[] = $session_id;
        } elseif (!empty($session_id) && $this->column_exists($table, 'consultation_session_id')) {
            $session_clause = ' AND consultation_session_id = %s';
            $session_args[] = $session_id;
        }

        if ($this->column_exists($table, 'lead_verified')) {
            $count = (int) $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM {$table} WHERE user_id = %d AND source IN ('lead_generation','vmo_ai_discovery') AND lead_verified = 1{$session_clause}",
                array_merge(array($user_id), $session_args)
            ));
        } else {
            $count = (int) $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM {$table} WHERE user_id = %d AND source IN ('lead_generation','vmo_ai_discovery') AND (acquisition_details IS NULL OR acquisition_details NOT LIKE %s){$session_clause}",
                array_merge(array($user_id, '%template%'), $session_args)
            ));
        }

        return array(
            'label' => 'Verified CRM leads',
            'ready' => $count > 0,
            'reason' => $count > 0 ? 'Real AI-discovered leads are present in CRM.' : ($this->lead_research_configured() ? 'No non-template CRM leads have been verified.' : 'Lead generation requires API configuration or live research access.'),
            'details' => array('verified_leads_count' => $count, 'research_configured' => $this->lead_research_configured()),
        );
    }

    private function lead_research_configured() {
        return (bool) get_option('vmo_openai_api_key')
            || (bool) get_option('openai_api_key')
            || (bool) get_option('vmo_perplexity_api_key')
            || (bool) get_option('vmo_serpapi_key');
    }

    private function evaluate_kpis($user_id, $session_id, array $context) {
        $targets = get_user_meta($user_id, 'vmo_kpi_targets', true);
        if (!is_array($targets)) {
            $targets = array();
        }
        $count = 0;
        foreach ($targets as $target) {
            if (is_array($target) && (isset($target['target_value']) || isset($target['value']) || isset($target['recommended_action']))) {
                $count++;
            }
        }

        return array(
            'label' => 'KPI targets and dashboard data',
            'ready' => $count > 0,
            'reason' => $count > 0 ? 'KPI targets are stored for dashboard tracking.' : 'KPI targets have not been created for the business dashboard.',
            'details' => array('targets_count' => $count),
        );
    }

    private function evaluate_today($user_id, $session_id, array $context) {
        $actions = $this->count_table_rows('vmo_actions', 'user_id = %d AND status IN (\'pending\',\'in_progress\')', array($user_id));
        $activities = $this->count_table_rows('vmo_daily_activities', 'user_id = %d AND status IN (\'pending\',\'in_progress\')', array($user_id));

        return array(
            'label' => 'Today tab',
            'ready' => ($actions + $activities) > 0,
            'reason' => ($actions + $activities) > 0 ? 'Today tab has actionable tasks.' : 'No pending Today tasks or daily activities were found.',
            'details' => array('actions_count' => $actions, 'daily_activities_count' => $activities),
        );
    }

    private function evaluate_dashboard($user_id, $session_id, array $context) {
        global $wpdb;
        $manifest = $this->array_path($context, array('business_manifest'), array());
        $state = $this->array_path($context, array('operating_state'), array());
        $tools = array(
            'manifest' => !empty($manifest),
            'operating_state' => !empty($state),
            'kpi_targets' => !empty(get_user_meta($user_id, 'vmo_kpi_targets', true)),
            'business_dashboard_class' => class_exists('VMO_Business_Dashboard') || class_exists('VMO_Business_Manifest_Generator'),
            'orders_ledger_table' => $this->table_exists($wpdb->prefix . 'vmo_store_orders'),
            'business_flow_instances_table' => $this->table_exists($wpdb->prefix . 'vmo_business_flow_instances'),
            'fulfillment_tasks_table' => $this->table_exists($wpdb->prefix . 'vmo_fulfillment_tasks'),
            'transaction_links_table' => $this->table_exists($wpdb->prefix . 'vmo_transaction_links'),
            'transaction_flow_links_table' => $this->table_exists($wpdb->prefix . 'vmo_transaction_flow_links'),
            'cfo_briefing_class' => class_exists('VMO_Tax_Calculator') || (defined('VMO_AI_BUILDER_DIR') && file_exists(VMO_AI_BUILDER_DIR . 'includes/class-vmo-tax-calculator.php')),
            'payments_report_class' => class_exists('VMO_Stripe_Connect') || (defined('VMO_AI_BUILDER_DIR') && file_exists(VMO_AI_BUILDER_DIR . 'includes/class-vmo-stripe-connect.php')),
        );
        $ready = !in_array(false, $tools, true);

        return array(
            'label' => 'Dashboard tools',
            'ready' => $ready,
            'reason' => $ready ? 'Dashboard manifest, operating state, KPI contracts, order ledger, business-flow bridge tables, and CFO/payment reporting are ready.' : 'Dashboard manifest, operating state, KPI contracts, order ledger, business-flow bridge tables, CFO reporting, payment reporting, or dashboard class readiness is incomplete.',
            'details' => $tools,
        );
    }

    private function evaluate_launch_tour($user_id, $session_id, array $context) {
        $state = get_user_meta($user_id, 'vmo_launch_tour_state_' . $session_id, true);
        $script = get_user_meta($user_id, 'vmo_launch_tour_script_' . $session_id, true);
        $audio_url = get_user_meta($user_id, 'vmo_launch_tour_audio_url_' . $session_id, true);
        $ready = is_array($state)
            && !empty($state['script_ready'])
            && !empty($state['audio_ready'])
            && !empty($state['audio_url'])
            && !empty($script)
            && !empty($audio_url);

        return array(
            'label' => 'Final VMO launch tour',
            'ready' => $ready,
            'reason' => $ready ? 'Launch tour script and audio are generated and stored.' : 'Final launch tour script/audio is not generated yet.',
            'details' => is_array($state) ? $state : array('script_ready' => !empty($script), 'audio_ready' => !empty($audio_url)),
        );
    }

    private function approved_pages_count(array $context, array $state, array $website_data) {
        $candidates = array(
            $state['approved_pages_count'] ?? null,
            $state['planned_pages_count'] ?? null,
            $website_data['approved_pages_count'] ?? null,
            $website_data['planned_pages_count'] ?? null,
            $this->array_path($context, array('website_architecture', 'approved_pages_count'), null),
        );
        foreach ($candidates as $candidate) {
            $count = intval($candidate);
            if ($count > 0) {
                return $count;
            }
        }

        $page_sets = array(
            $this->array_path($context, array('approved_website_architecture', 'pages'), array()),
            $this->array_path($context, array('website_architecture', 'approved_pages'), array()),
            $this->array_path($context, array('website_architecture', 'pages'), array()),
        );
        foreach ($page_sets as $pages) {
            if (is_array($pages) && !empty($pages)) {
                return count($pages);
            }
        }

        return 0;
    }

    private function active_store_product_count($user_id, $session_id = '') {
        global $wpdb;
        $table = $wpdb->prefix . 'vmo_store_products';
        if (!$this->table_exists($table)) {
            return 0;
        }
        $session_clause = '';
        $args = array($user_id);
        if (!empty($session_id) && $this->column_exists($table, 'session_id')) {
            $session_clause = ' AND session_id = %s';
            $args[] = $session_id;
        } elseif (!empty($session_id) && $this->column_exists($table, 'consultation_session_id')) {
            $session_clause = ' AND consultation_session_id = %s';
            $args[] = $session_id;
        }
        return (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$table} WHERE user_id = %d AND status = 'active' AND price_cents > 0{$session_clause}",
            $args
        ));
    }

    private function payments_required(array $context) {
        $payment_state = $this->array_path($context, array('operating_state', 'systems', 'payments'), array());
        if (!empty($payment_state['enabled']) || !empty($payment_state['checkout_ready']) || !empty($payment_state['products_count'])) {
            return true;
        }
        $intent = strtolower((string) $this->array_path($context, array('extracted_information', 'payment_requirements'), ''));
        $business_type = strtolower((string) $this->array_path($context, array('extracted_information', 'business_type'), ''));
        $products = $this->array_path($context, array('extracted_information', 'products_inventory'), array());
        return strpos($intent, 'payment') !== false || strpos($intent, 'checkout') !== false || !empty($products) || strpos($business_type, 'ecommerce') !== false || strpos($business_type, 'store') !== false;
    }

    private function catalog_required(array $context) {
        $products = $this->array_path($context, array('extracted_information', 'products_inventory'), array());
        $services = $this->array_path($context, array('extracted_information', 'services_inventory'), array());
        $offerings = $this->array_path($context, array('extracted_information', 'offerings'), array());
        $business_type = strtolower((string) $this->array_path($context, array('extracted_information', 'business_type'), ''));
        return !empty($products) || !empty($services) || !empty($offerings) || strpos($business_type, 'ecommerce') !== false || strpos($business_type, 'store') !== false;
    }

    private function needs_shipping_policy(array $context) {
        $shipping = strtolower((string) $this->array_path($context, array('extracted_information', 'shipping_requirements'), ''));
        $products = $this->array_path($context, array('extracted_information', 'products_inventory'), array());
        return !empty($products) || strpos($shipping, 'ship') !== false || strpos($shipping, 'delivery') !== false;
    }

    private function stored_document_types($user_id, $session_id = '') {
        global $wpdb;
        $types = array();

        $business_table = $wpdb->prefix . 'vmo_business_documents';
        if ($this->table_exists($business_table)) {
            $session_clause = '';
            $args = array($user_id);
            if (!empty($session_id) && $this->column_exists($business_table, 'session_id')) {
                $session_clause = ' AND session_id = %s';
                $args[] = $session_id;
            } elseif (!empty($session_id) && $this->column_exists($business_table, 'consultation_session_id')) {
                $session_clause = ' AND consultation_session_id = %s';
                $args[] = $session_id;
            }
            $rows = $wpdb->get_col($wpdb->prepare("SELECT doc_type FROM {$business_table} WHERE user_id = %d{$session_clause}", $args));
            foreach ($rows as $type) {
                $types[] = $this->normalize_doc_type($type);
            }
        }

        $legal_table = $wpdb->prefix . 'vmo_legal_documents';
        if ($this->table_exists($legal_table)) {
            $session_clause = '';
            $args = array($user_id);
            if (!empty($session_id) && $this->column_exists($legal_table, 'session_id')) {
                $session_clause = ' AND session_id = %s';
                $args[] = $session_id;
            } elseif (!empty($session_id) && $this->column_exists($legal_table, 'consultation_session_id')) {
                $session_clause = ' AND consultation_session_id = %s';
                $args[] = $session_id;
            }
            $rows = $wpdb->get_col($wpdb->prepare("SELECT doc_type FROM {$legal_table} WHERE user_id = %d{$session_clause}", $args));
            foreach ($rows as $type) {
                $types[] = $this->normalize_doc_type($type);
            }
        }

        return array_values(array_unique(array_filter($types)));
    }

    private function normalize_doc_type($type) {
        $type = sanitize_key((string) $type);
        $aliases = array(
            'terms_and_conditions' => 'terms_of_service',
            'terms_conditions' => 'terms_of_service',
            'phone_email_guide' => 'phone_email_setup_guide',
            'seo_strategy' => 'seo_plan',
            'marketing_strategy' => 'marketing_plan',
        );
        return $aliases[$type] ?? $type;
    }

    private function array_has_demo_items($items) {
        if (!is_array($items)) {
            return false;
        }
        foreach ($items as $item) {
            if (!is_array($item)) {
                continue;
            }
            $flags = array('demo', 'is_demo', 'sample', 'placeholder');
            foreach ($flags as $flag) {
                if (!empty($item[$flag])) {
                    return true;
                }
            }
        }
        return false;
    }

    private function count_table_rows($table_suffix, $where_sql, array $args) {
        global $wpdb;
        $table = $wpdb->prefix . $table_suffix;
        if (!$this->table_exists($table)) {
            return 0;
        }
        $sql = "SELECT COUNT(*) FROM {$table} WHERE {$where_sql}";
        if (!empty($args)) {
            $sql = $wpdb->prepare($sql, $args);
        }
        return (int) $wpdb->get_var($sql);
    }

    private function table_exists($table) {
        global $wpdb;
        return $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)) === $table;
    }

    private function column_exists($table, $column) {
        global $wpdb;
        return $wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$table} LIKE %s", $column)) === $column;
    }

    private function decode_maybe_json($value) {
        if (is_array($value)) {
            return $value;
        }
        if (!is_string($value) || trim($value) === '') {
            return array();
        }
        $decoded = json_decode($value, true);
        if (is_array($decoded)) {
            return $decoded;
        }
        $maybe = maybe_unserialize($value);
        return is_array($maybe) ? $maybe : array();
    }

    private function array_path(array $array, array $path, $default = null) {
        $cursor = $array;
        foreach ($path as $key) {
            if (!is_array($cursor) || !array_key_exists($key, $cursor)) {
                return $default;
            }
            $cursor = $cursor[$key];
        }
        return $cursor;
    }
}