<?php
/**
 * 247ChatMate — Agency Hub client setup PDF upload.
 * Checkpoint: AGENCYPDFOBJECTSTREAMREADFIX1LOCK
 *
 * Purpose:
 * - Let an approved agency upload a completed client setup PDF from Agency Hub.
 * - Store the uploaded PDF through WordPress media/upload handling.
 * - Link the stored PDF reference to a selected local client setup pack.
 * - Or create a new draft client setup pack from the uploaded PDF and attach it.
 * - Read structured/fillable PDF fields from the 247ChatMate setup form and prefill the draft pack.
 *
 * Does not:
 * - Run OCR, call AI/external APIs, auto-create paid licences, alter widgets,
 *   change chips, change WhatsApp handoff, change lead routing or change trials/licensing.
 */

defined('ABSPATH') || exit;

if (!defined('MATEWA_AGENCY_CLIENT_PDF_UPLOADS_OPTION')) {
    define('MATEWA_AGENCY_CLIENT_PDF_UPLOADS_OPTION', 'matewa_agency_client_pdf_uploads');
}

if (!function_exists('matewa_agency_client_pdf_clean_record')) {
    function matewa_agency_client_pdf_clean_record($record, $pack_id = '') {
        $record = is_array($record) ? $record : array();
        $pack_id = '' !== $pack_id ? sanitize_key((string) $pack_id) : (isset($record['setup_pack_id']) ? sanitize_key((string) $record['setup_pack_id']) : '');

        if ('' === $pack_id) {
            return array();
        }

        $attachment_id = isset($record['attachment_id']) ? absint($record['attachment_id']) : 0;
        $file_url = isset($record['file_url']) ? esc_url_raw((string) $record['file_url']) : '';

        if ($attachment_id > 0) {
            $attachment_url = wp_get_attachment_url($attachment_id);
            if ($attachment_url) {
                $file_url = esc_url_raw($attachment_url);
            }
        }

        $extracted_fields = array();
        if (isset($record['extracted_fields']) && is_array($record['extracted_fields'])) {
            foreach ($record['extracted_fields'] as $field_key => $field_value) {
                $field_key = sanitize_key((string) $field_key);
                if ('' === $field_key || !is_scalar($field_value)) {
                    continue;
                }
                $extracted_fields[$field_key] = sanitize_textarea_field((string) $field_value);
            }
        }

        return array(
            'setup_pack_id' => $pack_id,
            'attachment_id' => $attachment_id,
            'file_name'     => isset($record['file_name']) ? sanitize_file_name((string) $record['file_name']) : '',
            'file_url'      => $file_url,
            'file_type'     => 'application/pdf',
            'uploaded_at'   => isset($record['uploaded_at']) ? absint($record['uploaded_at']) : 0,
            'uploaded_by'   => isset($record['uploaded_by']) ? absint($record['uploaded_by']) : 0,
            'extracted_at'  => isset($record['extracted_at']) ? absint($record['extracted_at']) : 0,
            'extracted_field_count' => isset($record['extracted_field_count']) ? absint($record['extracted_field_count']) : 0,
            'extracted_fields' => $extracted_fields,
        );
    }
}

if (!function_exists('matewa_agency_client_pdf_get_records')) {
    function matewa_agency_client_pdf_get_records() {
        $records = get_option(MATEWA_AGENCY_CLIENT_PDF_UPLOADS_OPTION, array());
        $records = is_array($records) ? $records : array();
        $safe = array();

        foreach ($records as $pack_id => $record) {
            $clean = matewa_agency_client_pdf_clean_record($record, $pack_id);
            if (!empty($clean['setup_pack_id']) && !empty($clean['attachment_id'])) {
                $safe[$clean['setup_pack_id']] = $clean;
            }
        }

        return $safe;
    }
}

if (!function_exists('matewa_agency_client_pdf_store_records')) {
    function matewa_agency_client_pdf_store_records($records) {
        $records = is_array($records) ? $records : array();
        $safe = array();

        foreach ($records as $pack_id => $record) {
            $clean = matewa_agency_client_pdf_clean_record($record, $pack_id);
            if (!empty($clean['setup_pack_id']) && !empty($clean['attachment_id'])) {
                $safe[$clean['setup_pack_id']] = $clean;
            }
        }

        update_option(MATEWA_AGENCY_CLIENT_PDF_UPLOADS_OPTION, $safe, false);
        return true;
    }
}

if (!function_exists('matewa_agency_client_pdf_get_record_for_pack')) {
    function matewa_agency_client_pdf_get_record_for_pack($pack_id) {
        $pack_id = sanitize_key((string) $pack_id);
        if ('' === $pack_id) {
            return array();
        }

        $records = matewa_agency_client_pdf_get_records();
        return isset($records[$pack_id]) ? $records[$pack_id] : array();
    }
}

if (!function_exists('matewa_agency_client_pdf_pack_exists')) {
    function matewa_agency_client_pdf_pack_exists($pack_id) {
        $pack_id = sanitize_key((string) $pack_id);
        if ('' === $pack_id || !function_exists('matewa_agency_client_pack_get_records')) {
            return false;
        }

        foreach (matewa_agency_client_pack_get_records() as $record) {
            $record_id = isset($record['setup_pack_id']) ? sanitize_key((string) $record['setup_pack_id']) : '';
            if ('' !== $record_id && hash_equals($record_id, $pack_id)) {
                return true;
            }
        }

        return false;
    }
}


if (!function_exists('matewa_agency_client_pdf_has_available_bundle_seat')) {
    function matewa_agency_client_pdf_has_available_bundle_seat() {
        if (!function_exists('matewa_agency_bundle_get_records') || !function_exists('matewa_agency_client_pack_find_available_bundle_index')) {
            return false;
        }

        $bundle_records = matewa_agency_bundle_get_records();
        return matewa_agency_client_pack_find_available_bundle_index($bundle_records) >= 0;
    }
}

if (!function_exists('matewa_agency_client_pdf_draft_name_from_file')) {
    function matewa_agency_client_pdf_draft_name_from_file($file_name) {
        $file_name = sanitize_file_name((string) $file_name);
        $base = preg_replace('/\.pdf$/i', '', $file_name);
        $base = preg_replace('/[\-_]+/', ' ', (string) $base);
        $base = preg_replace('/\b(247chatmate|client|setup|form|completed|complete|pdf|review|copy|final)\b/i', ' ', (string) $base);
        $base = preg_replace('/\s+/', ' ', (string) $base);
        $base = trim((string) $base, " \t\n\r\0\x0B-_");

        if ('' === $base) {
            return 'PDF Review - ' . date_i18n('j M Y H:i');
        }

        $base = sanitize_text_field($base);
        if (function_exists('mb_substr')) {
            $base = mb_substr($base, 0, 72);
        } else {
            $base = substr($base, 0, 72);
        }

        return trim($base);
    }
}

if (!function_exists('matewa_agency_client_pdf_decode_pdf_string_value')) {
    function matewa_agency_client_pdf_decode_pdf_string_value($raw) {
        $raw = (string) $raw;
        $out = '';
        $length = strlen($raw);

        for ($i = 0; $i < $length; $i++) {
            $char = $raw[$i];
            if ('\\' !== $char) {
                $out .= $char;
                continue;
            }

            $i++;
            if ($i >= $length) {
                break;
            }

            $next = $raw[$i];
            if (preg_match('/[0-7]/', $next)) {
                $octal = $next;
                for ($j = 0; $j < 2 && ($i + 1) < $length && preg_match('/[0-7]/', $raw[$i + 1]); $j++) {
                    $i++;
                    $octal .= $raw[$i];
                }
                $out .= chr(octdec($octal));
                continue;
            }

            switch ($next) {
                case 'n':
                    $out .= "\n";
                    break;
                case 'r':
                    $out .= "\r";
                    break;
                case 't':
                    $out .= "\t";
                    break;
                case 'b':
                    $out .= "\x08";
                    break;
                case 'f':
                    $out .= "\x0c";
                    break;
                case '(':
                case ')':
                case '\\':
                    $out .= $next;
                    break;
                case "\r":
                    if (($i + 1) < $length && "\n" === $raw[$i + 1]) {
                        $i++;
                    }
                    break;
                case "\n":
                    break;
                default:
                    $out .= $next;
                    break;
            }
        }

        if (strlen($out) >= 2 && "\xfe\xff" === substr($out, 0, 2) && function_exists('mb_convert_encoding')) {
            $converted = @mb_convert_encoding(substr($out, 2), 'UTF-8', 'UTF-16BE');
            if (is_string($converted) && '' !== $converted) {
                $out = $converted;
            }
        }

        $out = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]+/', ' ', (string) $out);
        $out = preg_replace('/[ \t]+/', ' ', (string) $out);
        $out = preg_replace('/\s*\n\s*/', "\n", (string) $out);
        return trim((string) $out);
    }
}

if (!function_exists('matewa_agency_client_pdf_decode_pdf_hex_string')) {
    function matewa_agency_client_pdf_decode_pdf_hex_string($raw) {
        $hex = preg_replace('/[^0-9a-f]/i', '', (string) $raw);
        if ('' === $hex) {
            return '';
        }
        if (1 === (strlen($hex) % 2)) {
            $hex .= '0';
        }
        $bytes = @hex2bin($hex);
        if (!is_string($bytes)) {
            return '';
        }
        return matewa_agency_client_pdf_decode_pdf_string_value($bytes);
    }
}


if (!function_exists('matewa_agency_client_pdf_decode_pdf_name_token')) {
    function matewa_agency_client_pdf_decode_pdf_name_token($raw) {
        $raw = (string) $raw;
        $raw = preg_replace_callback('/#([0-9A-Fa-f]{2})/', function ($matches) {
            return chr(hexdec($matches[1]));
        }, $raw);
        $raw = str_replace(array(' ', '-'), '_', $raw);
        return $raw;
    }
}

if (!function_exists('matewa_agency_client_pdf_parse_objects')) {
    function matewa_agency_client_pdf_parse_objects($content) {
        $content = (string) $content;
        $objects = array();

        if (!preg_match_all('/(\d+)\s+(\d+)\s+obj\b(.*?)endobj/s', $content, $matches, PREG_SET_ORDER)) {
            return $objects;
        }

        foreach ($matches as $match) {
            $object_id = isset($match[1]) ? absint($match[1]) : 0;
            if ($object_id <= 0) {
                continue;
            }

            $objects[$object_id] = isset($match[3]) ? (string) $match[3] : '';
        }

        /*
         * Some PDF editors save form widgets inside compressed PDF object streams
         * (/Type /ObjStm). The first PDF import pass only inspected normal top-level
         * objects, so valid AcroForm fields such as business_name and business_type
         * could be missed even though the PDF still contained proper fillable fields.
         * Expand object streams into the same object map before field extraction.
         */
        $object_streams = $objects;
        foreach ($object_streams as $stream_object) {
            if (false === strpos($stream_object, '/ObjStm') || false === strpos($stream_object, 'stream')) {
                continue;
            }

            $first = null;
            $count = null;
            if (preg_match('/\/First\s+(\d+)/', $stream_object, $first_match)) {
                $first = isset($first_match[1]) ? absint($first_match[1]) : null;
            }
            if (preg_match('/\/N\s+(\d+)/', $stream_object, $count_match)) {
                $count = isset($count_match[1]) ? absint($count_match[1]) : null;
            }

            if (null === $first || null === $count || $first <= 0 || $count <= 0 || $count > 300) {
                continue;
            }

            $decoded = function_exists('matewa_agency_client_pdf_decode_stream_data') ? matewa_agency_client_pdf_decode_stream_data($stream_object) : '';
            if (!is_string($decoded) || '' === $decoded || strlen($decoded) <= $first) {
                continue;
            }

            $header = substr($decoded, 0, $first);
            $body = substr($decoded, $first);
            $tokens = preg_split('/\s+/', trim((string) $header));
            $tokens = is_array($tokens) ? array_values(array_filter($tokens, 'strlen')) : array();

            if (count($tokens) < ($count * 2)) {
                continue;
            }

            $pairs = array();
            for ($i = 0; $i < ($count * 2); $i += 2) {
                if (!isset($tokens[$i], $tokens[$i + 1]) || !is_numeric($tokens[$i]) || !is_numeric($tokens[$i + 1])) {
                    continue 2;
                }
                $pairs[] = array(absint($tokens[$i]), absint($tokens[$i + 1]));
            }

            $body_length = strlen($body);
            foreach ($pairs as $index => $pair) {
                $embedded_object_id = isset($pair[0]) ? absint($pair[0]) : 0;
                $offset = isset($pair[1]) ? absint($pair[1]) : 0;
                if ($embedded_object_id <= 0 || $offset < 0 || $offset >= $body_length) {
                    continue;
                }

                $next_offset = $body_length;
                if (isset($pairs[$index + 1][1])) {
                    $next_offset = absint($pairs[$index + 1][1]);
                }
                if ($next_offset <= $offset || $next_offset > $body_length) {
                    $next_offset = $body_length;
                }

                $embedded_object = trim((string) substr($body, $offset, $next_offset - $offset));
                if ('' === $embedded_object) {
                    continue;
                }

                $objects[$embedded_object_id] = $embedded_object;
            }
        }

        ksort($objects, SORT_NUMERIC);
        return $objects;
    }
}

if (!function_exists('matewa_agency_client_pdf_read_token_after_key')) {
    function matewa_agency_client_pdf_read_token_after_key($source, $key) {
        $source = (string) $source;
        $key = (string) $key;
        $pattern = '/' . preg_quote($key, '/') . '(?![A-Za-z0-9_#])/';
        if (!preg_match($pattern, $source, $key_match, PREG_OFFSET_CAPTURE)) {
            return null;
        }
        $pos = isset($key_match[0][1]) ? (int) $key_match[0][1] : -1;
        if ($pos < 0) {
            return null;
        }

        $i = $pos + strlen($key);
        $length = strlen($source);
        while ($i < $length && preg_match('/\s/', $source[$i])) {
            $i++;
        }
        if ($i >= $length) {
            return null;
        }

        $char = $source[$i];
        if ('(' === $char) {
            $i++;
            $depth = 1;
            $raw = '';
            while ($i < $length && $depth > 0) {
                $c = $source[$i];
                if ('\\' === $c) {
                    $raw .= $c;
                    $i++;
                    if ($i < $length) {
                        $raw .= $source[$i];
                        if (preg_match('/[0-7]/', $source[$i])) {
                            for ($j = 0; $j < 2 && ($i + 1) < $length && preg_match('/[0-7]/', $source[$i + 1]); $j++) {
                                $i++;
                                $raw .= $source[$i];
                            }
                        }
                    }
                    $i++;
                    continue;
                }
                if ('(' === $c) {
                    $depth++;
                    $raw .= $c;
                    $i++;
                    continue;
                }
                if (')' === $c) {
                    $depth--;
                    if ($depth > 0) {
                        $raw .= $c;
                    }
                    $i++;
                    continue;
                }
                $raw .= $c;
                $i++;
            }
            return matewa_agency_client_pdf_decode_pdf_string_value($raw);
        }

        if ('<' === $char && (($i + 1) >= $length || '<' !== $source[$i + 1])) {
            $end = strpos($source, '>', $i + 1);
            if (false === $end) {
                return null;
            }
            return matewa_agency_client_pdf_decode_pdf_hex_string(substr($source, $i + 1, $end - $i - 1));
        }

        if ('/' === $char) {
            $i++;
            $raw = '';
            while ($i < $length && !preg_match('/[\s<>\[\]\(\)\/]/', $source[$i])) {
                $raw .= $source[$i];
                $i++;
            }
            return sanitize_key(matewa_agency_client_pdf_decode_pdf_name_token($raw));
        }

        $raw = '';
        while ($i < $length && !preg_match('/\s/', $source[$i])) {
            $raw .= $source[$i];
            $i++;
        }
        return trim($raw);
    }
}


if (!function_exists('matewa_agency_client_pdf_ascii85_decode')) {
    function matewa_agency_client_pdf_ascii85_decode($data) {
        $data = preg_replace('/\s+/', '', (string) $data);
        $data = str_replace(array('<~', '~>'), '', $data);
        $out = '';
        $group = array();
        $length = strlen($data);

        for ($i = 0; $i < $length; $i++) {
            $ch = $data[$i];
            if ('z' === $ch && empty($group)) {
                $out .= "\0\0\0\0";
                continue;
            }
            $ord = ord($ch);
            if ($ord < 33 || $ord > 117) {
                continue;
            }
            $group[] = $ord - 33;
            if (5 === count($group)) {
                $value = 0;
                foreach ($group as $digit) {
                    $value = ($value * 85) + $digit;
                }
                $out .= chr(($value >> 24) & 255) . chr(($value >> 16) & 255) . chr(($value >> 8) & 255) . chr($value & 255);
                $group = array();
            }
        }

        if (!empty($group)) {
            $count = count($group);
            while (count($group) < 5) {
                $group[] = 84;
            }
            $value = 0;
            foreach ($group as $digit) {
                $value = ($value * 85) + $digit;
            }
            $bytes = chr(($value >> 24) & 255) . chr(($value >> 16) & 255) . chr(($value >> 8) & 255) . chr($value & 255);
            $out .= substr($bytes, 0, max(0, $count - 1));
        }

        return $out;
    }
}

if (!function_exists('matewa_agency_client_pdf_decode_stream_data')) {
    function matewa_agency_client_pdf_decode_stream_data($object) {
        $object = (string) $object;
        if (!preg_match('/stream\r?\n(.*?)\r?\nendstream/s', $object, $stream_match)) {
            if (!preg_match('/stream\r(.*?)\rendstream/s', $object, $stream_match)) {
                return '';
            }
        }

        $data = isset($stream_match[1]) ? (string) $stream_match[1] : '';
        if ('' === $data) {
            return '';
        }

        $filters = array();
        if (preg_match('/\/Filter\s*\[([^\]]+)\]/s', $object, $filter_match)) {
            if (preg_match_all('/\/([A-Za-z0-9]+)/', $filter_match[1], $filter_names)) {
                $filters = $filter_names[1];
            }
        } elseif (preg_match('/\/Filter\s*\/([A-Za-z0-9]+)/', $object, $filter_match)) {
            $filters = array($filter_match[1]);
        }

        foreach ($filters as $filter) {
            $filter = (string) $filter;
            if ('ASCII85Decode' === $filter || 'A85' === $filter) {
                $data = matewa_agency_client_pdf_ascii85_decode($data);
            } elseif ('FlateDecode' === $filter || 'Fl' === $filter) {
                $decoded = @gzuncompress($data);
                if (!is_string($decoded)) {
                    $decoded = @gzinflate($data);
                }
                if (!is_string($decoded)) {
                    $decoded = @gzdecode($data);
                }
                if (is_string($decoded) && '' !== $decoded) {
                    $data = $decoded;
                }
            }
        }

        return is_string($data) ? $data : '';
    }
}

if (!function_exists('matewa_agency_client_pdf_extract_text_chunks_from_stream')) {
    function matewa_agency_client_pdf_extract_text_chunks_from_stream($stream) {
        $stream = (string) $stream;
        if ('' === $stream) {
            return array();
        }

        $chunks = array();

        if (preg_match_all('/\(((?:\\.|[^\\()])*)\)\s*Tj\b/s', $stream, $matches)) {
            foreach ($matches[1] as $raw) {
                $text = matewa_agency_client_pdf_decode_pdf_string_value($raw);
                $text = trim(preg_replace('/\s+/', ' ', (string) $text));
                if ('' !== $text) {
                    $chunks[] = $text;
                }
            }
        }

        if (preg_match_all('/<([0-9A-Fa-f\s]+)>\s*Tj\b/s', $stream, $matches)) {
            foreach ($matches[1] as $raw) {
                $text = matewa_agency_client_pdf_decode_pdf_hex_string($raw);
                $text = trim(preg_replace('/\s+/', ' ', (string) $text));
                if ('' !== $text) {
                    $chunks[] = $text;
                }
            }
        }

        if (preg_match_all('/\[(.*?)\]\s*TJ\b/s', $stream, $matches)) {
            foreach ($matches[1] as $array_source) {
                $parts = array();
                if (preg_match_all('/\(((?:\\.|[^\\()])*)\)|<([0-9A-Fa-f\s]+)>/s', $array_source, $part_matches, PREG_SET_ORDER)) {
                    foreach ($part_matches as $part) {
                        if (isset($part[1]) && '' !== $part[1]) {
                            $parts[] = matewa_agency_client_pdf_decode_pdf_string_value($part[1]);
                        } elseif (isset($part[2]) && '' !== $part[2]) {
                            $parts[] = matewa_agency_client_pdf_decode_pdf_hex_string($part[2]);
                        }
                    }
                }
                $text = trim(preg_replace('/\s+/', ' ', implode('', $parts)));
                if ('' !== $text) {
                    $chunks[] = $text;
                }
            }
        }

        $out = array();
        foreach ($chunks as $chunk) {
            $chunk = trim(wp_strip_all_tags((string) $chunk));
            if ('' === $chunk) {
                continue;
            }
            $out[] = $chunk;
        }

        return array_values(array_unique($out));
    }
}

if (!function_exists('matewa_agency_client_pdf_first_safe_appearance_text')) {
    function matewa_agency_client_pdf_first_safe_appearance_text($texts) {
        $texts = is_array($texts) ? $texts : array();
        foreach ($texts as $text) {
            $text = trim((string) $text);
            if ('' === $text) {
                continue;
            }
            $normal = strtolower($text);
            if (in_array($normal, array('off', 'yes', 'on', 'true', 'false'), true)) {
                continue;
            }
            if (strlen($text) > 500) {
                $text = substr($text, 0, 500);
            }
            return $text;
        }
        return '';
    }
}

if (!function_exists('matewa_agency_client_pdf_extract_fillable_fields_from_file')) {
    function matewa_agency_client_pdf_extract_fillable_fields_from_file($file_path) {
        $file_path = (string) $file_path;
        if ('' === $file_path || !is_readable($file_path)) {
            return array();
        }

        $size = @filesize($file_path);
        if (false !== $size && $size > 12 * 1024 * 1024) {
            return array();
        }

        $content = @file_get_contents($file_path);
        if (!is_string($content) || '' === $content) {
            return array();
        }

        $wanted = array(
            'business_name' => true,
            'website_domain' => true,
            'client_contact_name' => true,
            'main_admin_email' => true,
            'leads_email' => true,
            'whatsapp_mobile' => true,
            'business_type' => true,
            'country_language' => true,
            'placement_homepage' => true,
            'placement_all_pages' => true,
            'placement_specific_pages' => true,
            'visitor_button_notes' => true,
            'google_business_profile' => true,
            'instagram_link' => true,
            'facebook_link' => true,
            'review_link' => true,
            'additional_notes' => true,
            'confirm_correct' => true,
            'confirmed_by' => true,
            'confirmed_date' => true,
        );
        for ($i = 1; $i <= 8; $i++) {
            $wanted['page_' . $i] = true;
        }

        $fields = array();
        $objects = matewa_agency_client_pdf_parse_objects($content);
        $parsed_objects = array();

        foreach ($objects as $object_id => $object) {
            if (false === strpos($object, '/T') && false === strpos($object, '/V') && false === strpos($object, '/Parent') && false === strpos($object, 'stream')) {
                continue;
            }

            $name = matewa_agency_client_pdf_read_token_after_key($object, '/T');
            $name = is_scalar($name) ? sanitize_key((string) $name) : '';
            $value = matewa_agency_client_pdf_read_token_after_key($object, '/V');
            $has_value = null !== $value;

            $parent_id = 0;
            if (preg_match('/\/Parent\s+(\d+)\s+\d+\s+R\b/', $object, $parent_match)) {
                $parent_id = isset($parent_match[1]) ? absint($parent_match[1]) : 0;
            }

            $appearance_id = 0;
            if (preg_match('/\/AP\s*<<.*?\/N\s+(\d+)\s+\d+\s+R.*?>>/s', $object, $appearance_match)) {
                $appearance_id = isset($appearance_match[1]) ? absint($appearance_match[1]) : 0;
            }

            $stream_texts = array();
            if (function_exists('matewa_agency_client_pdf_decode_stream_data') && function_exists('matewa_agency_client_pdf_extract_text_chunks_from_stream')) {
                $stream_texts = matewa_agency_client_pdf_extract_text_chunks_from_stream(matewa_agency_client_pdf_decode_stream_data($object));
            }

            $parsed_objects[$object_id] = array(
                'name' => $name,
                'value' => $has_value && is_scalar($value) ? trim((string) $value) : '',
                'has_value' => $has_value,
                'parent_id' => $parent_id,
                'appearance_id' => $appearance_id,
                'stream_texts' => $stream_texts,
            );
        }

        /* First pass: standard AcroForm fields where /T and /V live in the same object. */
        foreach ($parsed_objects as $parsed) {
            $name = isset($parsed['name']) ? sanitize_key((string) $parsed['name']) : '';
            if ('' === $name || !isset($wanted[$name]) || empty($parsed['has_value'])) {
                continue;
            }

            $value = isset($parsed['value']) && is_scalar($parsed['value']) ? trim((string) $parsed['value']) : '';
            if (!isset($fields[$name]) || '' === $fields[$name] || '' !== $value) {
                $fields[$name] = $value;
            }
        }

        /* Second pass: some PDF editors save /V on a child widget and keep /T on the parent field. */
        foreach ($parsed_objects as $parsed) {
            if (empty($parsed['has_value'])) {
                continue;
            }

            $name = isset($parsed['name']) ? sanitize_key((string) $parsed['name']) : '';
            if ('' === $name && !empty($parsed['parent_id']) && isset($parsed_objects[$parsed['parent_id']]['name'])) {
                $name = sanitize_key((string) $parsed_objects[$parsed['parent_id']]['name']);
            }

            if ('' === $name || !isset($wanted[$name])) {
                continue;
            }

            $value = isset($parsed['value']) && is_scalar($parsed['value']) ? trim((string) $parsed['value']) : '';
            if (!isset($fields[$name]) || '' === $fields[$name] || '' !== $value) {
                $fields[$name] = $value;
            }
        }

        /* Third pass: if a parent has a value but a child provided the display name, keep the non-empty value. */
        foreach ($parsed_objects as $object_id => $parsed) {
            if (!empty($parsed['has_value']) || empty($parsed['name'])) {
                continue;
            }

            $name = sanitize_key((string) $parsed['name']);
            if ('' === $name || !isset($wanted[$name])) {
                continue;
            }

            foreach ($parsed_objects as $child) {
                $child_parent = isset($child['parent_id']) ? absint($child['parent_id']) : 0;
                if ($child_parent !== absint($object_id) || empty($child['has_value'])) {
                    continue;
                }

                $value = isset($child['value']) && is_scalar($child['value']) ? trim((string) $child['value']) : '';
                if (!isset($fields[$name]) || '' === $fields[$name] || '' !== $value) {
                    $fields[$name] = $value;
                }
            }
        }

        /* Fourth pass: recover values from PDF appearance streams when a PDF editor draws text but does not save /V cleanly. */
        foreach ($parsed_objects as $object_id => $parsed) {
            $name = isset($parsed['name']) ? sanitize_key((string) $parsed['name']) : '';
            if ('' === $name || !isset($wanted[$name])) {
                continue;
            }

            if (isset($fields[$name]) && '' !== trim((string) $fields[$name]) && 'off' !== sanitize_key((string) $fields[$name])) {
                continue;
            }

            $appearance_text = '';
            if (!empty($parsed['stream_texts']) && function_exists('matewa_agency_client_pdf_first_safe_appearance_text')) {
                $appearance_text = matewa_agency_client_pdf_first_safe_appearance_text($parsed['stream_texts']);
            }

            $appearance_id = isset($parsed['appearance_id']) ? absint($parsed['appearance_id']) : 0;
            if ('' === $appearance_text && $appearance_id > 0 && isset($parsed_objects[$appearance_id]['stream_texts']) && function_exists('matewa_agency_client_pdf_first_safe_appearance_text')) {
                $appearance_text = matewa_agency_client_pdf_first_safe_appearance_text($parsed_objects[$appearance_id]['stream_texts']);
            }

            if ('' === $appearance_text) {
                $next_id = absint($object_id) + 1;
                if (isset($parsed_objects[$next_id]['stream_texts']) && function_exists('matewa_agency_client_pdf_first_safe_appearance_text')) {
                    $appearance_text = matewa_agency_client_pdf_first_safe_appearance_text($parsed_objects[$next_id]['stream_texts']);
                }
            }

            if ('' !== $appearance_text) {
                $fields[$name] = $appearance_text;
            }
        }

        foreach ($wanted as $wanted_name => $_enabled) {
            if (!isset($fields[$wanted_name])) {
                $fields[$wanted_name] = '';
            }
        }

        foreach ($fields as $field_name => $value) {
            if (0 === strpos($field_name, 'placement_') || in_array($field_name, array('confirm_correct'), true)) {
                $value = sanitize_key((string) $value);
                $fields[$field_name] = in_array($value, array('yes', 'on', 'true', '1'), true) ? 'yes' : 'off';
            } else {
                $value = wp_strip_all_tags((string) $value);
                $value = str_replace(array("\r\n", "\r"), "\n", $value);
                $value = preg_replace('/[ \t]+/', ' ', $value);
                $fields[$field_name] = trim((string) $value);
            }
        }

        return $fields;
    }
}

if (!function_exists('matewa_agency_client_pdf_field_value')) {
    function matewa_agency_client_pdf_field_value($fields, $key) {
        $fields = is_array($fields) ? $fields : array();
        $key = sanitize_key((string) $key);
        return isset($fields[$key]) && is_scalar($fields[$key]) ? trim((string) $fields[$key]) : '';
    }
}

if (!function_exists('matewa_agency_client_pdf_checkbox_is_on')) {
    function matewa_agency_client_pdf_checkbox_is_on($fields, $key) {
        $value = sanitize_key(matewa_agency_client_pdf_field_value($fields, $key));
        return in_array($value, array('yes', 'on', 'true', '1'), true);
    }
}

if (!function_exists('matewa_agency_client_pdf_build_page_items_from_fields')) {
    function matewa_agency_client_pdf_build_page_items_from_fields($fields, $client_domain = '') {
        $fields = is_array($fields) ? $fields : array();
        $client_domain = function_exists('matewa_agency_client_pack_normalise_domain') ? matewa_agency_client_pack_normalise_domain($client_domain) : sanitize_text_field((string) $client_domain);
        $pages = array();

        for ($i = 1; $i <= 8; $i++) {
            $raw = matewa_agency_client_pdf_field_value($fields, 'page_' . $i);
            if ('' === $raw) {
                continue;
            }

            $raw = trim($raw);
            if ('' !== $client_domain && 0 === strpos($raw, '/')) {
                $raw = 'https://' . $client_domain . '/' . ltrim($raw, '/');
            } elseif ('' !== $client_domain && !preg_match('#^https?://#i', $raw) && false === strpos($raw, '.')) {
                $raw = 'https://' . $client_domain . '/' . ltrim($raw, '/');
            }

            $url = function_exists('matewa_agency_client_pack_clean_page_url') ? matewa_agency_client_pack_clean_page_url($raw, $client_domain) : esc_url_raw($raw);
            if ('' === $url) {
                continue;
            }

            $path = wp_parse_url($url, PHP_URL_PATH);
            $path = trim((string) $path, '/');
            $title = '' === $path ? 'Homepage' : ucwords(str_replace(array('-', '_', '/'), ' ', $path));
            $pages[] = array(
                'url' => $url,
                'title' => $title,
                'source' => 'pdf',
            );
        }

        return function_exists('matewa_agency_client_pack_clean_page_list') ? matewa_agency_client_pack_clean_page_list($pages, $client_domain, 8) : $pages;
    }
}

if (!function_exists('matewa_agency_client_pdf_build_import_data_from_fields')) {
    function matewa_agency_client_pdf_build_import_data_from_fields($fields, $file_name = '', $business_type_hint = '') {
        $fields = is_array($fields) ? $fields : array();

        $client_business = sanitize_text_field(matewa_agency_client_pdf_field_value($fields, 'business_name'));
        $client_domain = function_exists('matewa_agency_client_pack_normalise_domain') ? matewa_agency_client_pack_normalise_domain(matewa_agency_client_pdf_field_value($fields, 'website_domain')) : sanitize_text_field(matewa_agency_client_pdf_field_value($fields, 'website_domain'));
        $client_admin_email = sanitize_email(matewa_agency_client_pdf_field_value($fields, 'main_admin_email'));
        $leads_email = sanitize_email(matewa_agency_client_pdf_field_value($fields, 'leads_email'));
        $whatsapp_number = function_exists('matewa_agency_client_pack_clean_phone') ? matewa_agency_client_pack_clean_phone(matewa_agency_client_pdf_field_value($fields, 'whatsapp_mobile')) : sanitize_text_field(matewa_agency_client_pdf_field_value($fields, 'whatsapp_mobile'));
        $business_type_text = sanitize_text_field(matewa_agency_client_pdf_field_value($fields, 'business_type'));

        $selected_pages = matewa_agency_client_pdf_build_page_items_from_fields($fields, $client_domain);
        if (!empty($selected_pages) || matewa_agency_client_pdf_checkbox_is_on($fields, 'placement_specific_pages')) {
            $page_mode = 'specific_pages';
        } elseif (matewa_agency_client_pdf_checkbox_is_on($fields, 'placement_homepage')) {
            $page_mode = 'homepage';
        } else {
            $page_mode = 'all_pages';
        }

        $raw_summary = array();
        foreach (array(
            'business_name', 'website_domain', 'main_admin_email', 'leads_email', 'whatsapp_mobile', 'business_type', 'country_language',
            'visitor_button_notes', 'google_business_profile', 'instagram_link', 'facebook_link', 'review_link', 'additional_notes', 'confirmed_by', 'confirmed_date'
        ) as $field_key) {
            $value = matewa_agency_client_pdf_field_value($fields, $field_key);
            if ('' !== $value) {
                $raw_summary[$field_key] = sanitize_textarea_field($value);
            }
        }

        $found = 0;
        foreach ($fields as $value) {
            if (is_scalar($value) && '' !== trim((string) $value) && 'off' !== sanitize_key((string) $value)) {
                $found++;
            }
        }

        return array(
            'client_business' => $client_business,
            'client_domain' => $client_domain,
            'client_admin_email' => $client_admin_email,
            'leads_email' => $leads_email,
            'whatsapp_number' => $whatsapp_number,
            'business_type_text' => $business_type_text,
            'country_language' => sanitize_text_field(matewa_agency_client_pdf_field_value($fields, 'country_language')),
            'page_mode' => $page_mode,
            'detected_pages' => $selected_pages,
            'selected_pages' => $selected_pages,
            'extracted_fields' => $raw_summary,
            'extracted_field_count' => absint($found),
            'has_extracted_fields' => $found > 0,
        );
    }
}


if (!function_exists('matewa_agency_client_pdf_match_normalise_text')) {
    function matewa_agency_client_pdf_match_normalise_text($value) {
        $value = is_scalar($value) ? (string) $value : '';
        $value = html_entity_decode(wp_strip_all_tags($value), ENT_QUOTES, 'UTF-8');
        $value = strtolower($value);
        $value = str_replace(array('&', '+'), ' and ', $value);
        $value = preg_replace('/[^a-z0-9]+/i', ' ', (string) $value);
        $value = preg_replace('/\s+/', ' ', (string) $value);
        return trim((string) $value);
    }
}

if (!function_exists('matewa_agency_client_pdf_match_text_contains_phrase')) {
    function matewa_agency_client_pdf_match_text_contains_phrase($haystack, $phrase) {
        $haystack = ' ' . matewa_agency_client_pdf_match_normalise_text($haystack) . ' ';
        $phrase = matewa_agency_client_pdf_match_normalise_text($phrase);

        if ('' === $phrase) {
            return false;
        }

        if (false !== strpos($haystack, ' ' . $phrase . ' ')) {
            return true;
        }

        $words = preg_split('/\s+/', $phrase);
        if (!is_array($words) || empty($words)) {
            return false;
        }

        $last_index = count($words) - 1;
        if (isset($words[$last_index]) && strlen((string) $words[$last_index]) > 3 && 's' !== substr((string) $words[$last_index], -1)) {
            $words[$last_index] .= 's';
            return false !== strpos($haystack, ' ' . implode(' ', $words) . ' ');
        }

        return false;
    }
}

if (!function_exists('matewa_agency_client_pdf_business_type_synonyms')) {
    function matewa_agency_client_pdf_business_type_synonyms() {
        return array(
            'aerial_installer'          => array('aerial installer', 'tv aerial', 'satellite installer', 'antenna installer'),
            'appliance_repair'         => array('appliance repair', 'appliance repairs', 'washing machine repair', 'oven repair', 'dishwasher repair'),
            'bathroom_fitter'          => array('bathroom fitter', 'bathroom fitters', 'bathroom installer', 'bathroom installation'),
            'builder'                  => array('builder', 'builders', 'building contractor', 'building work'),
            'car_dealer'               => array('car dealer', 'car dealers', 'used cars', 'used car', 'car sales', 'vehicle sales', 'motors', 'cars'),
            'car_detailing'            => array('car detailing', 'detailing', 'car valeting', 'valeting'),
            'car_repair'               => array('car repair', 'car repairs', 'mechanic', 'mechanics', 'garage', 'vehicle repair', 'vehicle repairs', 'auto repair'),
            'carpenter_joiner'         => array('carpenter', 'carpenters', 'joiner', 'joiners', 'joinery', 'carpentry'),
            'cleaner'                  => array('cleaner', 'cleaners', 'cleaning company', 'domestic cleaning', 'commercial cleaning'),
            'decorator'                => array('decorator', 'decorators', 'painter', 'painters', 'painting', 'decorating', 'painter decorator'),
            'painter_decorator'        => array('decorator', 'decorators', 'painter', 'painters', 'painting', 'decorating', 'painter decorator'),
            'drainage'                 => array('drainage', 'drains', 'blocked drain', 'blocked drains', 'drain unblocking'),
            'electric_gates'           => array('electric gates', 'gate automation', 'automated gates'),
            'electrician'              => array('electrician', 'electricians', 'electrical', 'electrical contractor', 'sparky'),
            'fencer'                   => array('fencer', 'fencing', 'fence installer', 'fence installation'),
            'flooring_installer'       => array('flooring installer', 'floor fitter', 'flooring', 'carpet fitter', 'laminate floor'),
            'gardener'                 => array('gardener', 'gardeners', 'gardening', 'garden maintenance'),
            'glazier'                  => array('glazier', 'glazing', 'glass repair', 'window glass'),
            'guttering_fascias_soffits'=> array('guttering', 'gutters', 'fascias', 'soffits', 'fascia soffit'),
            'handyman'                 => array('handyman', 'handy man', 'property maintenance'),
            'home_networking'          => array('home networking', 'wifi installer', 'network installer', 'home wifi'),
            'hvac'                     => array('hvac', 'air conditioning', 'air con', 'heating ventilation'),
            'it_services'              => array('it services', 'it support', 'computer support', 'managed it'),
            'landscaper'               => array('landscaper', 'landscapers', 'landscaping', 'garden design'),
            'locksmith'                => array('locksmith', 'locksmiths', 'locks', 'lock repair'),
            'mobile_mechanic'          => array('mobile mechanic', 'mobile mechanics', 'mobile car repair', 'mobile vehicle repair'),
            'mot_garage'               => array('mot garage', 'mot test', 'mot testing', 'mot'),
            'plasterer'                => array('plasterer', 'plasterers', 'plastering', 'renderer', 'rendering'),
            'plumber'                  => array('plumber', 'plumbers', 'plumbing', 'boiler', 'boilers', 'gas engineer', 'heating engineer', 'central heating'),
            'roofer'                   => array('roofer', 'roofers', 'roofing', 'roof repair', 'roof repairs', 'leaking roof'),
            'tiler'                    => array('tiler', 'tilers', 'tiling', 'wall tiling', 'floor tiling'),
            'tree_surgeon'             => array('tree surgeon', 'tree surgeons', 'tree surgery', 'arborist'),
            'tyre_fitting'             => array('tyre fitting', 'tyres', 'tyre', 'tire', 'tires'),
            'window_cleaner'           => array('window cleaner', 'window cleaners', 'window cleaning'),
            'window_door_installer'    => array('window installer', 'door installer', 'windows and doors', 'double glazing'),
        );
    }
}


if (!function_exists('matewa_agency_client_pdf_trade_match_groups')) {
    function matewa_agency_client_pdf_trade_match_groups() {
        return array(
            'plumber' => array(
                'source' => array('plumber', 'plumbers', 'plumbing', 'boiler', 'boilers', 'gas engineer', 'gas engineers', 'heating engineer', 'heating engineers', 'central heating'),
                'candidate' => array('plumber', 'plumbers', 'plumbing', 'boiler', 'boilers', 'gas', 'heating', 'central heating'),
            ),
            'electrician' => array(
                'source' => array('electrician', 'electricians', 'electrical', 'electrical contractor', 'sparky'),
                'candidate' => array('electrician', 'electricians', 'electrical', 'electric'),
            ),
            'roofer' => array(
                'source' => array('roofer', 'roofers', 'roofing', 'roof repair', 'leaking roof'),
                'candidate' => array('roofer', 'roofers', 'roofing', 'roof'),
            ),
            'car_dealer' => array(
                'source' => array('car dealer', 'used cars', 'used car', 'car sales', 'vehicle sales', 'jims cars', 'cars'),
                'candidate' => array('car dealer', 'used cars', 'used car', 'car sales', 'vehicle sales', 'dealer', 'dealership', 'motors'),
            ),
            'car_repair' => array(
                'source' => array('car repair', 'car repairs', 'mechanic', 'mechanics', 'garage', 'vehicle repair', 'auto repair'),
                'candidate' => array('car repair', 'vehicle repair', 'mechanic', 'garage', 'auto repair'),
            ),
            'mobile_mechanic' => array(
                'source' => array('mobile mechanic', 'mobile mechanics', 'mobile car repair', 'mobile vehicle repair'),
                'candidate' => array('mobile mechanic', 'mobile mechanics', 'mobile car repair', 'mobile vehicle repair'),
            ),
            'cleaner' => array(
                'source' => array('cleaner', 'cleaners', 'cleaning', 'domestic cleaning', 'commercial cleaning'),
                'candidate' => array('cleaner', 'cleaners', 'cleaning'),
            ),
            'gardener' => array(
                'source' => array('gardener', 'gardeners', 'gardening', 'garden maintenance'),
                'candidate' => array('gardener', 'gardeners', 'gardening', 'garden maintenance'),
            ),
            'locksmith' => array(
                'source' => array('locksmith', 'locksmiths', 'locks'),
                'candidate' => array('locksmith', 'locksmiths', 'locks'),
            ),
            'carpenter_joiner' => array(
                'source' => array('carpenter', 'carpenters', 'joiner', 'joiners', 'joinery', 'carpentry'),
                'candidate' => array('carpenter', 'carpenters', 'joiner', 'joiners', 'joinery', 'carpentry'),
            ),
            'builder' => array(
                'source' => array('builder', 'builders', 'building contractor', 'building work'),
                'candidate' => array('builder', 'builders', 'building contractor', 'building'),
            ),
        );
    }
}

if (!function_exists('matewa_agency_client_pdf_text_has_any_phrase')) {
    function matewa_agency_client_pdf_text_has_any_phrase($text, $phrases) {
        $phrases = is_array($phrases) ? $phrases : array();
        foreach ($phrases as $phrase) {
            if (matewa_agency_client_pdf_match_text_contains_phrase($text, $phrase)) {
                return true;
            }
        }
        return false;
    }
}

if (!function_exists('matewa_agency_client_pdf_match_business_type_from_text')) {
    function matewa_agency_client_pdf_match_business_type_from_text($source_text) {
        $source_text = matewa_agency_client_pdf_match_normalise_text($source_text);
        if ('' === $source_text || !function_exists('matewa_agency_client_pack_get_selector_data')) {
            return array();
        }

        $selector = matewa_agency_client_pack_get_selector_data();
        $categories = isset($selector['categories']) && is_array($selector['categories']) ? $selector['categories'] : array();
        $synonyms = matewa_agency_client_pdf_business_type_synonyms();
        $stop_words = array('and' => true, 'the' => true, 'for' => true, 'with' => true, 'setup' => true, 'pdf' => true, 'review' => true, 'test' => true, 'client' => true, 'business' => true, 'company' => true, 'limited' => true, 'ltd' => true, 'uk' => true, 'service' => true, 'services' => true);

        $best = array();
        $best_score = 0;

        foreach ($categories as $category_key => $category_data) {
            $category_key = sanitize_key((string) $category_key);
            $options = isset($category_data['options']) && is_array($category_data['options']) ? $category_data['options'] : array();

            foreach ($options as $vertical_key => $vertical_data) {
                $vertical_key = sanitize_key((string) $vertical_key);
                if ('' === $vertical_key || 'general' === $vertical_key) {
                    continue;
                }

                $label = isset($vertical_data['display_label']) ? sanitize_text_field((string) $vertical_data['display_label']) : ucwords(str_replace('_', ' ', $vertical_key));
                $phrases = array($vertical_key, str_replace('_', ' ', $vertical_key), $label);
                if (isset($synonyms[$vertical_key]) && is_array($synonyms[$vertical_key])) {
                    $phrases = array_merge($phrases, $synonyms[$vertical_key]);
                }

                $score = 0;
                $unique_phrases = array_unique(array_filter($phrases));

                foreach ($unique_phrases as $phrase) {
                    $normalised_phrase = matewa_agency_client_pdf_match_normalise_text($phrase);
                    if ('' !== $normalised_phrase && $source_text === $normalised_phrase) {
                        $exact_score = 240 + strlen($normalised_phrase);
                        if ($vertical_key === sanitize_key(str_replace(' ', '_', $normalised_phrase))) {
                            $exact_score += 30;
                        }
                        if (isset($synonyms[$vertical_key]) && in_array($phrase, $synonyms[$vertical_key], true)) {
                            $exact_score += 20;
                        }
                        $score = max($score, $exact_score);
                    }
                }

                foreach ($unique_phrases as $phrase) {
                    if (matewa_agency_client_pdf_match_text_contains_phrase($source_text, $phrase)) {
                        $phrase_score = 80 + strlen(matewa_agency_client_pdf_match_normalise_text($phrase));
                        if (isset($synonyms[$vertical_key]) && in_array($phrase, $synonyms[$vertical_key], true)) {
                            $phrase_score += 30;
                        }
                        $score = max($score, $phrase_score);
                    }
                }

                if ($score < 70) {
                    $tokens = preg_split('/\s+/', matewa_agency_client_pdf_match_normalise_text($label . ' ' . str_replace('_', ' ', $vertical_key)));
                    $tokens = is_array($tokens) ? array_values(array_unique(array_filter($tokens))) : array();
                    $meaningful = array();
                    foreach ($tokens as $token) {
                        $token = trim((string) $token);
                        if (strlen($token) < 4 || isset($stop_words[$token])) {
                            continue;
                        }
                        $meaningful[] = $token;
                    }

                    $hits = 0;
                    foreach ($meaningful as $token) {
                        if (matewa_agency_client_pdf_match_text_contains_phrase($source_text, $token)) {
                            $hits++;
                        }
                    }

                    if (!empty($meaningful) && $hits === count($meaningful)) {
                        $score = max($score, 70 + ($hits * 8));
                    } elseif ($hits >= 2) {
                        $score = max($score, 64 + ($hits * 6));
                    }
                }

                if ($score < 95 && function_exists('matewa_agency_client_pdf_trade_match_groups')) {
                    $candidate_text = $label . ' ' . str_replace('_', ' ', $vertical_key);
                    foreach (matewa_agency_client_pdf_trade_match_groups() as $trade_group) {
                        if (!is_array($trade_group)) {
                            continue;
                        }
                        $source_phrases = isset($trade_group['source']) && is_array($trade_group['source']) ? $trade_group['source'] : array();
                        $candidate_phrases = isset($trade_group['candidate']) && is_array($trade_group['candidate']) ? $trade_group['candidate'] : array();
                        if (matewa_agency_client_pdf_text_has_any_phrase($source_text, $source_phrases) && matewa_agency_client_pdf_text_has_any_phrase($candidate_text, $candidate_phrases)) {
                            $score = max($score, 118);
                            break;
                        }
                    }
                }

                if ($score > $best_score) {
                    $best_score = $score;
                    $best = array(
                        'category_key' => $category_key,
                        'vertical_key' => $vertical_key,
                        'vertical_label' => $label,
                        'score' => $score,
                    );
                }
            }
        }

        return $best_score >= 80 ? $best : array();
    }
}

if (!function_exists('matewa_agency_client_pdf_resolve_vertical_selection')) {
    function matewa_agency_client_pdf_resolve_vertical_selection($file_name, $business_type_hint = '', $pdf_business_type = '', $pdf_client_business = '') {
        $business_type_hint = sanitize_text_field((string) $business_type_hint);
        $pdf_business_type = sanitize_text_field((string) $pdf_business_type);
        $file_name = sanitize_file_name((string) $file_name);
        $sources = array();

        if ('' !== trim($pdf_business_type)) {
            $sources['pdf_field'] = $pdf_business_type;
        }

        if ('' !== trim($business_type_hint)) {
            $sources['hint'] = $business_type_hint;
        }

        if ('' !== trim($file_name)) {
            $sources['filename'] = preg_replace('/\.pdf$/i', '', $file_name);
        }

        foreach ($sources as $source => $text) {
            $match = matewa_agency_client_pdf_match_business_type_from_text($text);
            if (!empty($match['vertical_key']) && function_exists('matewa_agency_client_pack_resolve_vertical_selection')) {
                $selection = matewa_agency_client_pack_resolve_vertical_selection($match['category_key'], $match['vertical_key']);
                $selection['pdf_trade_match_source'] = $source;
                $selection['pdf_trade_match_score'] = isset($match['score']) ? absint($match['score']) : 0;
                return $selection;
            }
        }

        $selection = function_exists('matewa_agency_client_pack_resolve_vertical_selection')
            ? matewa_agency_client_pack_resolve_vertical_selection('', '')
            : array(
                'category_key'   => 'general',
                'category_label' => 'General',
                'vertical_key'   => 'general',
                'vertical_label' => 'General',
                'chips'          => array('Get a quote', 'Pricing', 'Availability', 'Ask a question', 'Book a job', 'Something else'),
            );
        $selection['pdf_trade_match_source'] = '';
        $selection['pdf_trade_match_score'] = 0;
        return $selection;
    }
}

if (!function_exists('matewa_agency_client_pdf_create_pending_pack')) {
    function matewa_agency_client_pdf_create_pending_pack($file_name, $business_type_hint = '', $pdf_import_data = array()) {
        if (!function_exists('matewa_agency_client_pack_get_records') || !function_exists('matewa_agency_client_pack_store_records') || !function_exists('matewa_agency_client_pack_find_available_bundle_index')) {
            return new WP_Error('pdf_new_pack_unavailable', 'Client setup pack storage is not available.');
        }

        if (!function_exists('matewa_agency_bundle_get_records') || !function_exists('matewa_agency_bundle_store_records')) {
            return new WP_Error('pdf_new_pack_unavailable', 'Agency bundle storage is not available.');
        }

        $bundle_records = matewa_agency_bundle_get_records();
        $bundle_index = matewa_agency_client_pack_find_available_bundle_index($bundle_records);

        if ($bundle_index < 0 || empty($bundle_records[$bundle_index]) || !is_array($bundle_records[$bundle_index])) {
            return new WP_Error('pdf_no_seats', 'No active client seats are available.');
        }

        $bundle = $bundle_records[$bundle_index];
        $bundle_id = isset($bundle['bundle_id']) ? sanitize_key((string) $bundle['bundle_id']) : '';
        $bundle_used = isset($bundle['used_seats']) ? absint($bundle['used_seats']) : 0;
        $bundle_seats = isset($bundle['seats']) ? absint($bundle['seats']) : 0;
        $now = time();

        $agency_summary = function_exists('matewa_agency_entitlement_get_summary') ? matewa_agency_entitlement_get_summary() : array();
        $agency_summary = is_array($agency_summary) ? $agency_summary : array();
        $agency_id = isset($agency_summary['agency_id']) ? sanitize_key((string) $agency_summary['agency_id']) : '';

        $pdf_import_data = is_array($pdf_import_data) ? $pdf_import_data : array();
        $pdf_business_type_text = isset($pdf_import_data['business_type_text']) ? sanitize_text_field((string) $pdf_import_data['business_type_text']) : '';
        $pdf_client_business = isset($pdf_import_data['client_business']) ? sanitize_text_field((string) $pdf_import_data['client_business']) : '';
        $vertical_selection = matewa_agency_client_pdf_resolve_vertical_selection($file_name, $business_type_hint, $pdf_business_type_text, $pdf_client_business);

        $existing_packs = matewa_agency_client_pack_get_records();
        $existing_ids = array();
        foreach ($existing_packs as $existing_pack) {
            if (is_array($existing_pack) && !empty($existing_pack['setup_pack_id'])) {
                $existing_ids[sanitize_key((string) $existing_pack['setup_pack_id'])] = true;
            }
        }

        $seed = $agency_id . '|pdf|' . sanitize_file_name((string) $file_name) . '|' . (string) $now . '|' . (string) wp_rand(10000, 999999);
        $pack_id = 'pack_' . substr(matewa_agency_client_pack_hash_value($seed), 0, 12);
        $guard = 0;
        while (isset($existing_ids[$pack_id]) && $guard < 10) {
            $seed .= '|' . (string) wp_rand(10000, 999999);
            $pack_id = 'pack_' . substr(matewa_agency_client_pack_hash_value($seed), 0, 12);
            $guard++;
        }

        if (isset($existing_ids[$pack_id])) {
            return new WP_Error('pdf_new_pack_unavailable', 'A unique setup pack ID could not be generated.');
        }

        $pdf_client_domain = isset($pdf_import_data['client_domain']) && function_exists('matewa_agency_client_pack_normalise_domain') ? matewa_agency_client_pack_normalise_domain((string) $pdf_import_data['client_domain']) : '';
        $pdf_client_admin_email = isset($pdf_import_data['client_admin_email']) ? sanitize_email((string) $pdf_import_data['client_admin_email']) : '';
        $pdf_whatsapp_number = isset($pdf_import_data['whatsapp_number']) && function_exists('matewa_agency_client_pack_clean_phone') ? matewa_agency_client_pack_clean_phone((string) $pdf_import_data['whatsapp_number']) : '';
        $pdf_leads_email = isset($pdf_import_data['leads_email']) ? sanitize_email((string) $pdf_import_data['leads_email']) : '';
        $pdf_page_mode = isset($pdf_import_data['page_mode']) && function_exists('matewa_agency_client_pack_allowed_page_mode') ? matewa_agency_client_pack_allowed_page_mode((string) $pdf_import_data['page_mode']) : 'all_pages';
        $pdf_detected_pages = isset($pdf_import_data['detected_pages']) && is_array($pdf_import_data['detected_pages']) && function_exists('matewa_agency_client_pack_clean_page_list') ? matewa_agency_client_pack_clean_page_list($pdf_import_data['detected_pages'], $pdf_client_domain, 8) : array();
        $pdf_selected_pages = isset($pdf_import_data['selected_pages']) && is_array($pdf_import_data['selected_pages']) && function_exists('matewa_agency_client_pack_clean_page_list') ? matewa_agency_client_pack_clean_page_list($pdf_import_data['selected_pages'], $pdf_client_domain, 8) : array();

        $data = array(
            'client_business'       => '' !== $pdf_client_business ? $pdf_client_business : matewa_agency_client_pdf_draft_name_from_file($file_name),
            'client_domain'         => $pdf_client_domain,
            'client_admin_email'    => $pdf_client_admin_email,
            'whatsapp_number'       => $pdf_whatsapp_number,
            'leads_email'           => $pdf_leads_email,
            'industry'              => isset($vertical_selection['category_label']) ? sanitize_text_field((string) $vertical_selection['category_label']) : 'General',
            'business_category'     => isset($vertical_selection['category_label']) ? sanitize_text_field((string) $vertical_selection['category_label']) : 'General',
            'business_category_key' => isset($vertical_selection['category_key']) ? sanitize_key((string) $vertical_selection['category_key']) : 'general',
            'business_type'         => isset($vertical_selection['vertical_label']) ? sanitize_text_field((string) $vertical_selection['vertical_label']) : 'General',
            'business_type_key'     => isset($vertical_selection['vertical_key']) ? sanitize_key((string) $vertical_selection['vertical_key']) : 'general',
            'page_mode'             => $pdf_page_mode,
            'detected_pages'        => $pdf_detected_pages,
            'selected_pages'        => $pdf_selected_pages,
            'chip_mode'             => 'defaults',
            'visitor_buttons'       => isset($vertical_selection['chips']) && is_array($vertical_selection['chips']) ? array_values($vertical_selection['chips']) : array(),
            'pdf_trade_match_source'=> isset($vertical_selection['pdf_trade_match_source']) ? sanitize_key((string) $vertical_selection['pdf_trade_match_source']) : '',
            'pdf_trade_match_score' => isset($vertical_selection['pdf_trade_match_score']) ? absint($vertical_selection['pdf_trade_match_score']) : 0,
        );

        $record = array_merge(array(
            'setup_pack_id'      => $pack_id,
            'agency_id'          => $agency_id,
            'assigned_bundle_id' => $bundle_id,
            'seat_status'        => 'assigned',
            'licence_status'     => 'draft',
            'expires_at'         => isset($bundle['expires_at']) ? sanitize_text_field((string) $bundle['expires_at']) : '',
            'renews_at'          => isset($bundle['renews_at']) ? sanitize_text_field((string) $bundle['renews_at']) : '',
            'status'             => 'pdf_uploaded_review',
            'created_at'         => $now,
            'updated_at'         => $now,
        ), $data);

        $existing_packs[] = $record;
        matewa_agency_client_pack_store_records($existing_packs);

        $bundle_records[$bundle_index]['used_seats'] = min($bundle_seats, $bundle_used + 1);
        $bundle_records[$bundle_index]['available_seats'] = max(0, $bundle_seats - absint($bundle_records[$bundle_index]['used_seats']));
        $bundle_records[$bundle_index]['updated_at'] = $now;
        matewa_agency_bundle_store_records($bundle_records);

        if (function_exists('matewa_agency_client_pack_reconcile_bundle_seats')) {
            matewa_agency_client_pack_reconcile_bundle_seats($existing_packs);
        }

        return $record;
    }
}

if (!function_exists('matewa_agency_client_pdf_notice_message')) {
    function matewa_agency_client_pdf_notice_message($code = '') {
        $code = sanitize_key((string) $code);
        $messages = array(
            'pdf_uploaded'         => 'Client setup PDF uploaded successfully.',
            'pdf_uploaded_new_pack'=> 'Client setup PDF uploaded and opened for review. Check the prefilled boxes, choose the right business type if needed, then save the setup pack.',
            'pdf_uploaded_new_pack_no_fields' => 'Client setup PDF uploaded and opened for review, but no fillable PDF fields were read. Fill the boxes manually or re-save the original fillable PDF and upload again.',
            'pdf_removed'          => 'Client setup PDF removed.',
            'pdf_missing_pack'     => 'Choose a saved client setup pack before uploading a PDF.',
            'pdf_pack_not_found'   => 'Client setup pack could not be found.',
            'pdf_missing_file'     => 'Choose a client setup PDF file before uploading.',
            'pdf_upload_failed'    => 'Client setup PDF could not be uploaded. Please try again.',
            'pdf_invalid_type'     => 'Please upload a PDF file only.',
            'pdf_agency_required'  => 'Agency Hub access is required before uploading client setup PDFs.',
            'pdf_removed_missing'  => 'No uploaded PDF was found for that setup pack.',
            'pdf_no_seats'         => 'No active client seats are available. Add or enable an agency bundle before starting a setup pack from PDF.',
            'pdf_new_pack_failed'  => 'Client setup PDF uploaded, but the new setup pack could not be started.',
            'pdf_new_pack_unavailable' => 'Client setup pack storage is not available right now.',
        );

        return isset($messages[$code]) ? $messages[$code] : ('' !== $code ? 'Client setup PDF status: ' . str_replace('_', ' ', $code) . '.' : '');
    }
}

if (!function_exists('matewa_agency_client_pdf_redirect')) {
    function matewa_agency_client_pdf_redirect($notice_code, $pack_id = '', $target = 'pdf_panel') {
        $args = array(
            'page'                            => '247chatmate',
            'matewa_saved_section'            => 'agency',
            'matewa_agency_client_pdf_notice' => sanitize_key((string) $notice_code),
        );

        $pack_id = sanitize_key((string) $pack_id);
        if ('' !== $pack_id) {
            $args['matewa_agency_pdf_pack'] = $pack_id;
        }

        $target = sanitize_key((string) $target);
        $anchor = '#matewa-agency-client-pdf-upload-panel';
        if ('edit_pack' === $target && '' !== $pack_id) {
            $args['matewa_agency_edit_pack'] = $pack_id;
            $anchor = '#matewa-agency-client-pack-editor';
        } elseif ('client_packs' === $target) {
            $anchor = '#matewa-agency-client-packs';
        } elseif ('pdf_list' === $target) {
            $anchor = '#matewa-agency-client-pdf-list';
        }

        wp_safe_redirect(add_query_arg($args, admin_url('admin.php')) . $anchor);
        exit;
    }
}

if (!function_exists('matewa_agency_client_pdf_handle_upload')) {
    function matewa_agency_client_pdf_handle_upload() {
        if (!current_user_can('manage_options')) {
            wp_die(esc_html__('You do not have permission to upload client setup PDFs.', '247chatmate'));
        }

        check_admin_referer('matewa_agency_client_pdf_upload', 'matewa_agency_client_pdf_nonce');

        $upload_mode = isset($_POST['matewa_agency_client_pdf_upload_mode']) ? sanitize_key(wp_unslash($_POST['matewa_agency_client_pdf_upload_mode'])) : 'existing_pack';
        $create_new_pack = 'new_pack' === $upload_mode;
        $pack_id = isset($_POST['matewa_agency_client_pdf_pack_id']) ? sanitize_key(wp_unslash($_POST['matewa_agency_client_pdf_pack_id'])) : '';
        $business_type_hint = isset($_POST['matewa_agency_client_pdf_business_type_hint']) && is_scalar($_POST['matewa_agency_client_pdf_business_type_hint']) ? sanitize_text_field(wp_unslash($_POST['matewa_agency_client_pdf_business_type_hint'])) : '';

        if (!function_exists('matewa_agency_hub_is_active') || !matewa_agency_hub_is_active()) {
            matewa_agency_client_pdf_redirect('pdf_agency_required', $pack_id);
        }

        if ($create_new_pack) {
            if (!matewa_agency_client_pdf_has_available_bundle_seat()) {
                matewa_agency_client_pdf_redirect('pdf_no_seats');
            }
        } else {
            if ('' === $pack_id) {
                matewa_agency_client_pdf_redirect('pdf_missing_pack');
            }

            if (!matewa_agency_client_pdf_pack_exists($pack_id)) {
                matewa_agency_client_pdf_redirect('pdf_pack_not_found', $pack_id);
            }
        }

        if (empty($_FILES['matewa_agency_client_pdf_file']) || !is_array($_FILES['matewa_agency_client_pdf_file'])) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File arrays are validated by the WordPress upload handler below.
            matewa_agency_client_pdf_redirect('pdf_missing_file', $pack_id);
        }

        $file = $_FILES['matewa_agency_client_pdf_file']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File arrays are validated by the WordPress upload handler below.
        $upload_error = isset($file['error']) ? absint($file['error']) : UPLOAD_ERR_NO_FILE;
        if (UPLOAD_ERR_OK !== $upload_error) {
            matewa_agency_client_pdf_redirect(UPLOAD_ERR_NO_FILE === $upload_error ? 'pdf_missing_file' : 'pdf_upload_failed', $pack_id);
        }

        $file_name = isset($file['name']) ? sanitize_file_name((string) $file['name']) : '';
        $tmp_name = isset($file['tmp_name']) ? (string) $file['tmp_name'] : '';

        if ('' === $file_name || '' === $tmp_name || !is_uploaded_file($tmp_name)) {
            matewa_agency_client_pdf_redirect('pdf_missing_file', $pack_id);
        }

        $allowed_mimes = array('pdf' => 'application/pdf');
        $checked = wp_check_filetype_and_ext($tmp_name, $file_name, $allowed_mimes);
        $checked_ext = isset($checked['ext']) ? strtolower((string) $checked['ext']) : '';
        $checked_type = isset($checked['type']) ? strtolower((string) $checked['type']) : '';

        if ('pdf' !== $checked_ext || 'application/pdf' !== $checked_type) {
            matewa_agency_client_pdf_redirect('pdf_invalid_type', $pack_id);
        }

        $pdf_raw_fields = function_exists('matewa_agency_client_pdf_extract_fillable_fields_from_file')
            ? matewa_agency_client_pdf_extract_fillable_fields_from_file($tmp_name)
            : array();
        $pdf_import_data = function_exists('matewa_agency_client_pdf_build_import_data_from_fields')
            ? matewa_agency_client_pdf_build_import_data_from_fields($pdf_raw_fields, $file_name, $business_type_hint)
            : array();
        $pdf_extracted_field_count = isset($pdf_import_data['extracted_field_count']) ? absint($pdf_import_data['extracted_field_count']) : 0;
        $pdf_extracted_fields = isset($pdf_import_data['extracted_fields']) && is_array($pdf_import_data['extracted_fields']) ? $pdf_import_data['extracted_fields'] : array();

        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/media.php';
        require_once ABSPATH . 'wp-admin/includes/image.php';

        $attachment_id = media_handle_upload(
            'matewa_agency_client_pdf_file',
            0,
            array(
                'post_title'   => preg_replace('/\.pdf$/i', '', $file_name),
                'post_content' => '247ChatMate Agency Hub client setup PDF.',
                'post_status'  => 'private',
            ),
            array(
                'test_form' => false,
                'mimes'     => $allowed_mimes,
            )
        );

        if (is_wp_error($attachment_id) || empty($attachment_id)) {
            matewa_agency_client_pdf_redirect('pdf_upload_failed', $pack_id);
        }

        $notice_code = 'pdf_uploaded';
        $previous_attachment_id = 0;

        if ($create_new_pack) {
            $created_pack = matewa_agency_client_pdf_create_pending_pack($file_name, $business_type_hint, $pdf_import_data);
            if (is_wp_error($created_pack) || !is_array($created_pack) || empty($created_pack['setup_pack_id'])) {
                wp_delete_attachment(absint($attachment_id), true);
                $error_code = is_wp_error($created_pack) ? sanitize_key($created_pack->get_error_code()) : 'pdf_new_pack_failed';
                matewa_agency_client_pdf_redirect($error_code ?: 'pdf_new_pack_failed');
            }

            $pack_id = sanitize_key((string) $created_pack['setup_pack_id']);
            $notice_code = $pdf_extracted_field_count > 0 ? 'pdf_uploaded_new_pack' : 'pdf_uploaded_new_pack_no_fields';
        }

        $records = matewa_agency_client_pdf_get_records();
        if (!$create_new_pack) {
            $previous_attachment_id = isset($records[$pack_id]['attachment_id']) ? absint($records[$pack_id]['attachment_id']) : 0;
        }

        $records[$pack_id] = array(
            'setup_pack_id' => $pack_id,
            'attachment_id' => absint($attachment_id),
            'file_name'     => $file_name,
            'file_url'      => wp_get_attachment_url($attachment_id),
            'file_type'     => 'application/pdf',
            'uploaded_at'   => time(),
            'uploaded_by'   => get_current_user_id(),
            'extracted_at'  => $pdf_extracted_field_count > 0 ? time() : 0,
            'extracted_field_count' => $pdf_extracted_field_count,
            'extracted_fields' => $pdf_extracted_fields,
        );
        matewa_agency_client_pdf_store_records($records);

        if ($previous_attachment_id > 0 && $previous_attachment_id !== absint($attachment_id)) {
            wp_delete_attachment($previous_attachment_id, true);
        }

        matewa_agency_client_pdf_redirect($notice_code, $pack_id, $create_new_pack ? 'edit_pack' : 'pdf_panel');
    }
}

add_action('admin_post_matewa_agency_upload_client_pdf', 'matewa_agency_client_pdf_handle_upload');

if (!function_exists('matewa_agency_client_pdf_handle_remove')) {
    function matewa_agency_client_pdf_handle_remove() {
        if (!current_user_can('manage_options')) {
            wp_die(esc_html__('You do not have permission to remove client setup PDFs.', '247chatmate'));
        }

        check_admin_referer('matewa_agency_client_pdf_remove', 'matewa_agency_client_pdf_remove_nonce');

        $pack_id = isset($_POST['matewa_agency_client_pdf_remove_pack_id']) ? sanitize_key(wp_unslash($_POST['matewa_agency_client_pdf_remove_pack_id'])) : '';

        if (!function_exists('matewa_agency_hub_is_active') || !matewa_agency_hub_is_active()) {
            matewa_agency_client_pdf_redirect('pdf_agency_required', $pack_id);
        }

        if ('' === $pack_id) {
            matewa_agency_client_pdf_redirect('pdf_missing_pack');
        }

        $records = matewa_agency_client_pdf_get_records();
        if (empty($records[$pack_id])) {
            matewa_agency_client_pdf_redirect('pdf_removed_missing', $pack_id);
        }

        $attachment_id = isset($records[$pack_id]['attachment_id']) ? absint($records[$pack_id]['attachment_id']) : 0;
        unset($records[$pack_id]);
        matewa_agency_client_pdf_store_records($records);

        if ($attachment_id > 0) {
            wp_delete_attachment($attachment_id, true);
        }

        matewa_agency_client_pdf_redirect('pdf_removed', $pack_id, 'pdf_list');
    }
}

add_action('admin_post_matewa_agency_remove_client_pdf', 'matewa_agency_client_pdf_handle_remove');

if (!function_exists('matewa_agency_client_pdf_render_panel')) {
    function matewa_agency_client_pdf_render_panel($client_pack_records = null) {
        $client_pack_records = null === $client_pack_records && function_exists('matewa_agency_client_pack_get_records')
            ? matewa_agency_client_pack_get_records()
            : (is_array($client_pack_records) ? array_values($client_pack_records) : array());
        $pdf_records = matewa_agency_client_pdf_get_records();

        $notice_code = isset($_GET['matewa_agency_client_pdf_notice']) && is_scalar($_GET['matewa_agency_client_pdf_notice'])
            ? sanitize_key(wp_unslash($_GET['matewa_agency_client_pdf_notice']))
            : '';
        $selected_pack_id = isset($_GET['matewa_agency_pdf_pack']) && is_scalar($_GET['matewa_agency_pdf_pack'])
            ? sanitize_key(wp_unslash($_GET['matewa_agency_pdf_pack']))
            : '';

        if ('' === $selected_pack_id && !empty($client_pack_records[0]['setup_pack_id'])) {
            $selected_pack_id = sanitize_key((string) $client_pack_records[0]['setup_pack_id']);
        }

        $valid_pack_ids = array();
        foreach ($client_pack_records as $pack) {
            if (is_array($pack) && !empty($pack['setup_pack_id'])) {
                $valid_pack_ids[] = sanitize_key((string) $pack['setup_pack_id']);
            }
        }
        $valid_pack_ids = array_values(array_unique(array_filter($valid_pack_ids)));
        $visible_pdf_records = array_intersect_key($pdf_records, array_flip($valid_pack_ids));

        $notice_message = '' !== $notice_code ? matewa_agency_client_pdf_notice_message($notice_code) : '';
        $notice_type = in_array($notice_code, array('pdf_uploaded', 'pdf_uploaded_new_pack', 'pdf_removed'), true) ? 'success' : 'warning';
        $has_packs = !empty($client_pack_records);
        $has_available_seat = matewa_agency_client_pdf_has_available_bundle_seat();
        $panel_open = '' !== $notice_code || !empty($visible_pdf_records);
        ?>
        <details id="matewa-agency-client-pdf-upload-panel" class="matewa-plan-access-section matewa-plan-access-section--support matewa-agency-client-pdf-upload-panel" aria-label="Client Setup PDF Upload" <?php echo $panel_open ? 'open' : ''; ?>>
            <summary>
                <span>Client Setup PDF Upload</span>
                <small>Upload Client Setup PDF</small>
            </summary>
            <div class="matewa-agency-client-pdf-upload-card">
                <div class="matewa-agency-client-pack-form-head">
                    <div>
                        <strong>Client Setup PDF Upload</strong>
                        <span>Upload the client’s completed setup PDF here. Fillable form fields are read where available, then a reviewable draft setup pack can be started.</span>
                    </div>
                    <em>Structured PDF import</em>
                </div>

                <?php if ('' !== $notice_message) : ?>
                    <div class="matewa-agency-bundle-notice is-<?php echo esc_attr($notice_type); ?>" role="status" aria-live="polite">
                        <?php echo esc_html($notice_message); ?>
                    </div>
                <?php endif; ?>

                <div class="matewa-agency-client-pdf-mode-grid" aria-label="Client setup PDF upload options">
                    <div class="matewa-agency-client-pdf-mode-card is-primary">
                        <div class="matewa-agency-client-pdf-mode-head">
                            <strong>Start new setup pack from PDF</strong>
                            <span>Creates a draft client setup pack, reserves one available client seat, attaches the PDF, and prefills fields from the structured PDF where available.</span>
                        </div>
                        <?php if (!$has_available_seat) : ?>
                            <div class="matewa-agency-client-pdf-empty">
                                <strong>No client seats available.</strong>
                                <span>Add or enable an agency bundle before starting a new setup pack from a PDF.</span>
                            </div>
                        <?php endif; ?>
                        <label class="matewa-agency-client-pdf-pack-select matewa-agency-client-pdf-trade-hint">
                            <span>Optional trade/business type hint</span>
                            <input type="text" name="matewa_agency_client_pdf_business_type_hint" form="matewa-agency-client-pdf-new-pack-form" placeholder="Example: plumber, electrician, car repair" autocomplete="off" spellcheck="false" <?php echo $has_available_seat ? '' : 'disabled'; ?>>
                            <small>Used only to preselect the closest business type and default chips. Leave blank to use filename matching or General.</small>
                        </label>
                        <div class="matewa-agency-client-pdf-dropzone" data-matewa-agency-pdf-dropzone>
                            <span class="dashicons dashicons-upload" aria-hidden="true"></span>
                            <strong>Drag and drop the completed client setup PDF here</strong>
                            <em>or</em>
                            <label class="matewa-agency-client-pdf-browse" for="matewa_agency_client_pdf_new_file">Browse files</label>
                            <input id="matewa_agency_client_pdf_new_file" type="file" name="matewa_agency_client_pdf_file" accept="application/pdf,.pdf" form="matewa-agency-client-pdf-new-pack-form" data-matewa-agency-pdf-file <?php echo $has_available_seat ? '' : 'disabled'; ?>>
                            <small data-matewa-agency-pdf-file-name>No PDF selected yet.</small>
                        </div>
                        <div class="matewa-agency-client-pack-actions matewa-agency-client-pdf-actions">
                            <button type="submit" class="button button-primary" form="matewa-agency-client-pdf-new-pack-form" <?php echo $has_available_seat ? '' : 'disabled'; ?>>Upload PDF &amp; Start New Client Setup Pack</button>
                            <small>This creates a reviewable draft record. Check the prefilled details before export/import.</small>
                        </div>
                    </div>

                    <div class="matewa-agency-client-pdf-mode-card">
                        <div class="matewa-agency-client-pdf-mode-head">
                            <strong>Attach or replace PDF on existing pack</strong>
                            <span>Use this when the client setup pack already exists and you only need to store or replace its source PDF.</span>
                        </div>
                        <?php if (!$has_packs) : ?>
                            <div class="matewa-agency-client-pdf-empty">
                                <strong>No existing setup packs yet.</strong>
                                <span>Use the new setup pack upload option first, or create a pack manually below.</span>
                            </div>
                        <?php else : ?>
                            <div class="matewa-agency-client-pdf-controls">
                                <label class="matewa-agency-client-pdf-pack-select">
                                    <span>Attach PDF to setup pack</span>
                                    <select name="matewa_agency_client_pdf_pack_id" form="matewa-agency-client-pdf-upload-form" data-matewa-agency-pdf-pack-select>
                                        <?php foreach ($client_pack_records as $pack) : ?>
                                            <?php
                                            $pack_id = isset($pack['setup_pack_id']) ? sanitize_key((string) $pack['setup_pack_id']) : '';
                                            if ('' === $pack_id) {
                                                continue;
                                            }
                                            $client_name = isset($pack['client_business']) && '' !== trim((string) $pack['client_business']) ? sanitize_text_field((string) $pack['client_business']) : 'Client';
                                            $client_domain = isset($pack['client_domain']) ? sanitize_text_field((string) $pack['client_domain']) : '';
                                            $option_label = $client_name . ('' !== $client_domain ? ' — ' . $client_domain : '') . ' · ' . $pack_id;
                                            ?>
                                            <option value="<?php echo esc_attr($pack_id); ?>" <?php selected($selected_pack_id, $pack_id); ?>><?php echo esc_html($option_label); ?></option>
                                        <?php endforeach; ?>
                                    </select>
                                </label>

                                <div class="matewa-agency-client-pdf-dropzone" data-matewa-agency-pdf-dropzone>
                                    <span class="dashicons dashicons-upload" aria-hidden="true"></span>
                                    <strong>Drag and drop the completed client setup PDF here</strong>
                                    <em>or</em>
                                    <label class="matewa-agency-client-pdf-browse" for="matewa_agency_client_pdf_file">Browse files</label>
                                    <input id="matewa_agency_client_pdf_file" type="file" name="matewa_agency_client_pdf_file" accept="application/pdf,.pdf" form="matewa-agency-client-pdf-upload-form" data-matewa-agency-pdf-file>
                                    <small data-matewa-agency-pdf-file-name>No PDF selected yet.</small>
                                </div>

                                <div class="matewa-agency-client-pack-actions matewa-agency-client-pdf-actions">
                                    <button type="submit" class="button button-primary" form="matewa-agency-client-pdf-upload-form">Upload Client Setup PDF</button>
                                    <small>Browse or drag in a PDF. Uploading another PDF for the same setup pack will replace the stored PDF reference.</small>
                                </div>
                            </div>
                        <?php endif; ?>
                    </div>
                </div>

                <div id="matewa-agency-client-pdf-list" class="matewa-agency-client-pdf-list" aria-label="Uploaded client setup PDFs">
                    <strong>Uploaded PDFs</strong>
                    <?php if (empty($visible_pdf_records)) : ?>
                        <p>No client setup PDFs uploaded yet.</p>
                    <?php else : ?>
                        <ul>
                            <?php foreach ($client_pack_records as $pack) : ?>
                                <?php
                                $pack_id = isset($pack['setup_pack_id']) ? sanitize_key((string) $pack['setup_pack_id']) : '';
                                if ('' === $pack_id || empty($pdf_records[$pack_id])) {
                                    continue;
                                }
                                $pdf_record = $pdf_records[$pack_id];
                                $client_name = isset($pack['client_business']) && '' !== trim((string) $pack['client_business']) ? sanitize_text_field((string) $pack['client_business']) : 'Client';
                                $file_name = isset($pdf_record['file_name']) && '' !== trim((string) $pdf_record['file_name']) ? sanitize_file_name((string) $pdf_record['file_name']) : 'Client setup PDF.pdf';
                                $file_url = isset($pdf_record['file_url']) ? esc_url_raw((string) $pdf_record['file_url']) : '';
                                $uploaded_at = isset($pdf_record['uploaded_at']) ? absint($pdf_record['uploaded_at']) : 0;
                                $extracted_count = isset($pdf_record['extracted_field_count']) ? absint($pdf_record['extracted_field_count']) : 0;
                                ?>
                                <li>
                                    <div>
                                        <span class="dashicons dashicons-media-document" aria-hidden="true"></span>
                                        <span>
                                            <strong><?php echo esc_html($client_name); ?></strong>
                                            <small><?php echo esc_html($file_name); ?><?php echo $uploaded_at > 0 ? esc_html(' · ' . date_i18n(get_option('date_format', 'j M Y') . ' ' . get_option('time_format', 'H:i'), $uploaded_at)) : ''; ?><?php echo $extracted_count > 0 ? esc_html(' · ' . $extracted_count . ' PDF fields read') : esc_html(' · no fillable fields read'); ?></small>
                                        </span>
                                    </div>
                                    <div class="matewa-agency-client-pdf-row-actions">
                                        <?php if ('' !== $file_url) : ?>
                                            <a class="button button-secondary" href="<?php echo esc_url($file_url); ?>" target="_blank" rel="noopener noreferrer">View / Open PDF</a>
                                        <?php endif; ?>
                                        <button type="submit" class="button button-secondary is-danger" form="matewa-agency-client-pdf-remove-form" name="matewa_agency_client_pdf_remove_pack_id" value="<?php echo esc_attr($pack_id); ?>" onclick="return window.confirm('Remove this uploaded client setup PDF?');">Remove PDF</button>
                                    </div>
                                </li>
                            <?php endforeach; ?>
                        </ul>
                    <?php endif; ?>
                </div>
            </div>
        </details>
        <?php
    }
}

if (!function_exists('matewa_agency_client_pdf_render_action_forms')) {
    function matewa_agency_client_pdf_render_action_forms() {
        ?>
        <form id="matewa-agency-client-pdf-new-pack-form" class="matewa-admin-hidden-action-form" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" enctype="multipart/form-data" aria-hidden="true">
            <input type="hidden" name="action" value="matewa_agency_upload_client_pdf">
            <input type="hidden" name="matewa_agency_client_pdf_upload_mode" value="new_pack">
            <?php wp_nonce_field('matewa_agency_client_pdf_upload', 'matewa_agency_client_pdf_nonce'); ?>
        </form>
        <form id="matewa-agency-client-pdf-upload-form" class="matewa-admin-hidden-action-form" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" enctype="multipart/form-data" aria-hidden="true">
            <input type="hidden" name="action" value="matewa_agency_upload_client_pdf">
            <input type="hidden" name="matewa_agency_client_pdf_upload_mode" value="existing_pack">
            <?php wp_nonce_field('matewa_agency_client_pdf_upload', 'matewa_agency_client_pdf_nonce'); ?>
        </form>
        <form id="matewa-agency-client-pdf-remove-form" class="matewa-admin-hidden-action-form" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" aria-hidden="true">
            <input type="hidden" name="action" value="matewa_agency_remove_client_pdf">
            <?php wp_nonce_field('matewa_agency_client_pdf_remove', 'matewa_agency_client_pdf_remove_nonce'); ?>
        </form>
        <?php
    }
}
