<?php

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Service for handling CSV and JSON imports, mapping fields, and inserting posts.
 */
class NEXDIRECTORY_Import_Service {

    /**
     * @var string
     */
    private $post_type;

    /**
     * @var NEXDIRECTORY_Date_Helper
     */
    private $date_helper;

    /**
     * @var NEXDIRECTORY_Event_Meta_Service
     */
    private $event_meta;

    /**
     * @var NEXDIRECTORY_Taxonomy_Service
     */
    private $taxonomy_service;

    /**
     * @var NEXDIRECTORY_User_Capabilities|null
     */
    private $user_caps;

    /**
     * Constructor.
     */
    public function __construct($post_type, $date_helper, $event_meta, $taxonomy_service, $user_caps = null) {
        $this->post_type = sanitize_key($post_type);
        $this->date_helper = $date_helper;
        $this->event_meta = $event_meta;
        $this->taxonomy_service = $taxonomy_service;
        $this->user_caps = $user_caps instanceof NEXDIRECTORY_User_Capabilities ? $user_caps : null;
    }

    /**
     * Returns a user-scoped transient key for import previews.
     *
     * @param string $token
     * @return string
     */
    public function get_import_preview_transient_key($token) {
        $token = substr(sanitize_key((string) $token), 0, 32);
        return 'nexdirectory_import_preview_' . absint((int) get_current_user_id()) . '_' . $token;
    }

    /**
     * Reads a temporary file and parses it as either JSON or CSV.
     */
    public function parse_import_payload($ext, $tmp_file) {
        $ext = strtolower((string) $ext);
        if (!is_uploaded_file($tmp_file) || !is_readable($tmp_file)) {
            return new WP_Error('upload_invalid', __('Uploaded file is not readable.', 'nexdirectory'));
        }

        $max_import_bytes = 10 * MB_IN_BYTES;
        $size_bytes = (int) @filesize($tmp_file); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
        if ($size_bytes > 0 && $size_bytes > $max_import_bytes) {
            /* translators: %d: Placeholder value. */
            return new WP_Error('import_too_large', sprintf(__('Import file is too large. Max allowed size is %d MB.', 'nexdirectory'), 10));
        }

        if ($ext === 'json') {
            $raw = file_get_contents($tmp_file); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reads a verified uploaded JSON temp file for import parsing.
            if ($raw === false) {
                return new WP_Error('read_error', __('Could not read uploaded JSON file.', 'nexdirectory'));
            }
            $decoded = json_decode($raw, true);
            if (!is_array($decoded)) {
                return new WP_Error('json_invalid', __('Invalid JSON payload.', 'nexdirectory'));
            }
            if (isset($decoded['events']) && is_array($decoded['events'])) {
                return $decoded['events'];
            }
            return $decoded;
        }

        if ($ext === 'csv') {
            try {
                $csv = new SplFileObject($tmp_file, 'r');
            } catch (RuntimeException $e) {
                return new WP_Error('read_error', __('Could not read uploaded CSV file.', 'nexdirectory'));
            }

            $max_rows = 5000;
            $rows = [];
            $headers = $csv->fgetcsv();
            if (!is_array($headers)) {
                return new WP_Error('csv_invalid', __('CSV header row is missing.', 'nexdirectory'));
            }

            $headers = array_map(static function ($h) {
                $h = preg_replace('/^\xEF\xBB\xBF/u', '', (string) $h); // Remove UTF-8 BOM
                return sanitize_key($h);
            }, $headers);

            while (!$csv->eof()) {
                $line = $csv->fgetcsv();
                if (!is_array($line)) {
                    continue;
                }
                if (count($line) === 1 && ($line[0] === null || $line[0] === false || trim((string) $line[0]) === '')) {
                    continue;
                }
                if (empty(array_filter($line, static function ($v) { return trim((string) $v) !== ''; }))) {
                    continue;
                }
                $line = array_slice($line, 0, count($headers));
                $assoc = array_combine($headers, array_pad($line, count($headers), ''));
                if (is_array($assoc)) {
                    $rows[] = $assoc;
                }
                if (count($rows) > $max_rows) {
                    /* translators: %d: Placeholder value. */
                    return new WP_Error('csv_too_many_rows', sprintf(__('CSV import is limited to %d rows per file.', 'nexdirectory'), $max_rows));
                }
            }
            return $rows;
        }

        return new WP_Error('unsupported', __('Unsupported import file type. Use .json or .csv', 'nexdirectory'));
    }

    /**
     * Extracts the distinct keys present in the data rows.
     */
    public function extract_import_headers($rows) {
        $headers = [];
        foreach (array_slice((array) $rows, 0, 100) as $row) {
            foreach ((array) $row as $key => $unused) {
                $k = sanitize_key((string) $key);
                if ($k !== '') {
                    $headers[$k] = $k;
                }
            }
        }
        return array_values($headers);
    }

    /**
     * Determines the optimal mapping between uploaded CSV headers and system fields.
     */
    public function guess_import_mapping($headers, array $ui_labels = []) {
        $header_keys = array_values(array_filter(array_map('sanitize_key', (array) $headers)));
        $header_map = array_fill_keys($header_keys, true);
        
        $aliases = [
            'title' => ['title', 'post_title', 'name', 'event_name', 'eventname'],
            'description' => ['description', 'content', 'post_content', 'details'],
            'excerpt' => ['excerpt', 'summary', 'post_excerpt', 'postexcerpt'],
            'meta_title' => ['meta_title', 'seo_title', 'nexdirectory_meta_title'],
            'meta_description' => ['meta_description', 'seo_description', 'nexdirectory_meta_description'],
            'start' => ['start', 'start_date', 'startdate', 'start_datetime', 'startdatetime', 'starts_at', 'startsat'],
            'end' => ['end', 'end_date', 'enddate', 'end_datetime', 'enddatetime', 'ends_at', 'endsat'],
            'timezone' => ['timezone', 'tz', 'time_zone'],
            'venue' => ['venue', 'location_name', 'locationname'],
            'address' => ['address', 'street_address', 'streetaddress'],
            'city' => ['city', 'town'],
            'country' => ['country', 'nation'],
            'lat' => ['lat', 'latitude'],
            'lng' => ['lng', 'lon', 'long', 'longitude'],
            'capacity' => ['capacity', 'max_attendees', 'maxattendees'],
            'price' => ['price', 'cost'],
            'ticket_sales_enabled' => ['ticket_sales_enabled', 'tickets_enabled', 'nexdirectory_ticket_sales_enabled'],
            'ticket_price' => ['ticket_price', 'nexdirectory_ticket_price'],
            'ticket_button_label' => ['ticket_button_label', 'nexdirectory_ticket_button_label'],
            'external_url' => ['external_url', 'externalurl', 'website', 'registration_url', 'registrationurl', 'url'],
            'stream_url' => ['stream_url', 'video_stream_url', 'livestream_url', 'live_stream_url'],
            'contact_email' => ['contact_email', 'contactemail', 'email'],
            'contact_phone' => ['contact_phone', 'contactphone', 'phone', 'telephone'],
            'contact_name' => ['contact_name', 'contactname', 'organizer', 'host_name', 'hostname'],
            'cover_image_url' => ['cover_image_url', 'coverimageurl', 'image_url', 'imageurl', 'cover'],
            'supporting_docs_urls' => ['supporting_docs_urls', 'supporting_docs', 'supportingdocs', 'document_urls', 'documents', 'docs', 'attachments'],
            'official_event' => ['official_event', 'officialevent', 'official'],
            'recurrence' => ['recurrence', 'repeat'],
            'recurrence_until' => ['recurrence_until', 'recurrenceuntil', 'repeat_until', 'repeatuntil'],
            'video_urls' => ['video_urls', 'videourls', 'videos', 'video'],
            'gallery_urls' => ['gallery_urls', 'galleryurls', 'gallery', 'images'],
            'sessions' => ['sessions', 'sessions_json', 'itinerary', 'itinerary_json', 'agenda', 'timeline', 'day_of_action', 'a_day_of_action'],
            'key_speakers' => ['key_speakers', 'key_speakers_json', 'key_speaker', 'keyspeaker', 'speakers', 'speakers_json', 'speaker_profiles', 'speaker_profiles_json', 'speaker'],
            'event_type' => ['event_type', 'eventtype', 'type'],
            'event_mode' => ['event_mode', 'eventmode', 'mode'],
            'event_price_range' => ['event_price_range', 'eventpricerange', 'price_range', 'pricerange'],
            'event_tags' => ['event_tags', 'eventtags', 'tags'],
            'custom_fields' => ['custom_fields', 'custom_field_values', 'nexdirectory_custom_fields_data'],
            'status' => ['status', 'post_status', 'poststatus'],
            'company_name' => ['company_name', 'company', 'employer', 'organization', 'organisation'],
            'job_type' => ['job_type', 'employment_type', 'employmenttype'],
            'job_work_mode' => ['job_work_mode', 'work_mode', 'workmode', 'location_type', 'locationtype'],
            'job_salary' => ['job_salary', 'salary', 'salary_range', 'salaryrange', 'compensation'],
            'job_apply_url' => ['job_apply_url', 'apply_url', 'application_url', 'applylink'],
            'job_application_email' => ['job_application_email', 'application_email', 'apply_email'],
            'job_closing_date' => ['job_closing_date', 'closing_date', 'deadline', 'application_deadline'],
            'job_department' => ['job_department', 'department', 'team'],
        ];

        $mapping = [];
        $supported_fields = $this->get_import_supported_fields($ui_labels);
        foreach (array_keys($supported_fields) as $target) {
            $mapping[$target] = '';
            foreach (($aliases[$target] ?? [$target]) as $alias) {
                $alias_key = sanitize_key((string) $alias);
                if (isset($header_map[$alias_key])) {
                    $mapping[$target] = $alias_key;
                    break;
                }
            }
        }

        return $mapping;
    }

    /**
     * Map of supported database keys and their human-readable labels.
     */
    public function get_import_supported_fields(array $ui_labels = []) {
        $singular = sanitize_text_field((string) ($ui_labels['singular'] ?? __('Event', 'nexdirectory')));
        $type_label = sanitize_text_field((string) ($ui_labels['taxonomy_type_plural'] ?? __('Event Types', 'nexdirectory')));
        $mode_label = sanitize_text_field((string) ($ui_labels['taxonomy_mode_plural'] ?? __('Event Modes', 'nexdirectory')));
        $tag_label = sanitize_text_field((string) ($ui_labels['taxonomy_tag_plural'] ?? __('Event Tags', 'nexdirectory')));
        
        return [
            /* translators: %s: Placeholder value. */
            'title' => sprintf(__('%s Title', 'nexdirectory'), $singular),
            'description' => __('Description / Main Content', 'nexdirectory'),
            'excerpt' => __('Short Excerpt', 'nexdirectory'),
            'meta_title' => __('Meta Title (SEO)', 'nexdirectory'),
            'meta_description' => __('Meta Description (SEO)', 'nexdirectory'),
            'start' => __('Start Date & Time', 'nexdirectory'),
            'end' => __('End Date & Time', 'nexdirectory'),
            'timezone' => __('Timezone', 'nexdirectory'),
            'venue' => __('Venue', 'nexdirectory'),
            'address' => __('Address', 'nexdirectory'),
            'city' => __('City', 'nexdirectory'),
            'country' => __('Country', 'nexdirectory'),
            'lat' => __('Latitude', 'nexdirectory'),
            'lng' => __('Longitude', 'nexdirectory'),
            'capacity' => __('Capacity', 'nexdirectory'),
            'price' => __('Price Label', 'nexdirectory'),
            'ticket_sales_enabled' => __('Ticket Sales Enabled', 'nexdirectory'),
            'ticket_price' => __('Ticket Price', 'nexdirectory'),
            'ticket_button_label' => __('Ticket Button Label', 'nexdirectory'),
            'external_url' => __('External URL', 'nexdirectory'),
            'stream_url' => __('Stream URL', 'nexdirectory'),
            'contact_email' => __('Contact Email', 'nexdirectory'),
            'contact_phone' => __('Contact Phone', 'nexdirectory'),
            'contact_name' => __('Contact Name', 'nexdirectory'),
            'cover_image_url' => __('Cover Image URL', 'nexdirectory'),
            'supporting_docs_urls' => __('Supporting Document URLs', 'nexdirectory'),
            /* translators: %s: Placeholder value. */
            'official_event' => sprintf(__('Official %s (Yes/No)', 'nexdirectory'), $singular),
            'recurrence' => __('Recurrence', 'nexdirectory'),
            'recurrence_until' => __('Recurrence Until', 'nexdirectory'),
            'video_urls' => __('Video URLs', 'nexdirectory'),
            'gallery_urls' => __('Gallery URLs', 'nexdirectory'),
            'sessions' => __('Sessions JSON', 'nexdirectory'),
            'key_speakers' => __('Key Speakers JSON', 'nexdirectory'),
            'event_type' => $type_label,
            'event_mode' => $mode_label,
            'event_price_range' => __('Price Range(s)', 'nexdirectory'),
            'event_tags' => $tag_label,
            'custom_fields' => __('Custom Fields JSON', 'nexdirectory'),
            'status' => __('Post Status', 'nexdirectory'),
            'company_name' => __('Company Name', 'nexdirectory'),
            'job_type' => __('Employment Type', 'nexdirectory'),
            'job_work_mode' => __('Work Setup', 'nexdirectory'),
            'job_salary' => __('Salary Range', 'nexdirectory'),
            'job_apply_url' => __('Application URL', 'nexdirectory'),
            'job_application_email' => __('Application Email', 'nexdirectory'),
            'job_closing_date' => __('Application Deadline', 'nexdirectory'),
            'job_department' => __('Department', 'nexdirectory'),
        ];
    }

    /**
     * Resolves the author ID to assign to imported posts.
     */
    public function get_default_import_author_id($preferred = 0) {
        $preferred = absint((int) $preferred);
        if ($preferred > 0 && get_user_by('id', $preferred) instanceof WP_User) {
            return $preferred;
        }

        $extension_author = absint((int) get_option('nexdirectory_extension_import_author_id', 0));
        if ($extension_author > 0 && get_user_by('id', $extension_author) instanceof WP_User) {
            return $extension_author;
        }

        $current = get_current_user_id();
        if ($current > 0) {
            return (int) $current;
        }

        $admins = get_users([
            'role' => 'administrator',
            'number' => 1,
            'orderby' => 'ID',
            'order' => 'ASC',
            'fields' => ['ID'],
        ]);
        
        if (!empty($admins) && isset($admins[0]) && $admins[0] instanceof WP_User) {
            return (int) $admins[0]->ID;
        }

        return 1;
    }

    /**
     * Reconstructs a clean row array based on the guessed mapping.
     */
    public function map_import_row_with_mapping($row, $mapping) {
        $row = $this->normalize_import_row($row);
        $mapped = [];
        foreach ((array) $mapping as $target => $source) {
            $target_key = sanitize_key((string) $target);
            $source_key = sanitize_key((string) $source);
            if ($target_key === '' || $source_key === '') continue;
            
            if (array_key_exists($source_key, $row)) {
                $mapped[$target_key] = $row[$source_key];
            }
        }
        return $mapped;
    }

    /**
     * Builds a normalized location signature for duplicate comparison.
     */
    private function normalize_event_location_signature($venue = '', $address = '', $city = '') {
        $parts = array_filter([
            sanitize_text_field((string) $venue),
            sanitize_text_field((string) $address),
            sanitize_text_field((string) $city),
        ], static function ($value) {
            return trim((string) $value) !== '';
        });
        if (empty($parts)) {
            return '';
        }
        $joined = strtolower(implode(' ', $parts));
        return trim((string) preg_replace('/\s+/u', ' ', $joined));
    }

    /**
     * Finds a possible duplicate event by title + start datetime (+ optional location signature).
     */
    public function find_duplicate_event_candidate($title, $start, $city = '', $address = '', $venue = '', $exclude_post_id = 0) {
        $title = sanitize_text_field((string) $title);
        $start = $this->date_helper->normalize_datetime_local($start);
        $exclude_post_id = absint((int) $exclude_post_id);
        if ($title === '' || $start === '') {
            return 0;
        }

        $input_signature = $this->normalize_event_location_signature($venue, $address, $city);
        $maybe = get_posts([
            'post_type' => $this->post_type,
            'post_status' => ['publish', 'pending', 'draft', 'private'],
            'posts_per_page' => 120,
            'fields' => 'ids',
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Duplicate detection intentionally performs one bounded exact-value lookup during an explicit import or submission validation request.
            'meta_query' => [
                [
                    'key' => 'nexdirectory_start',
                    'value' => $start,
                    'compare' => '=',
                ],
            ],
            'suppress_filters' => false,
            'no_found_rows' => true,
        ]);

        foreach ((array) $maybe as $maybe_id) {
            $maybe_id = (int) $maybe_id;
            if ($maybe_id <= 0 || $maybe_id === $exclude_post_id) {
                continue;
            }
            if (strcasecmp(trim((string) get_the_title($maybe_id)), trim($title)) !== 0) {
                continue;
            }
            if ($input_signature === '') {
                return $maybe_id;
            }
            $candidate_signature = $this->normalize_event_location_signature(
                get_post_meta($maybe_id, 'nexdirectory_venue', true),
                get_post_meta($maybe_id, 'nexdirectory_address', true),
                get_post_meta($maybe_id, 'nexdirectory_city', true)
            );
            if ($candidate_signature === '' || $candidate_signature === $input_signature) {
                return $maybe_id;
            }
            if (strpos($candidate_signature, $input_signature) !== false || strpos($input_signature, $candidate_signature) !== false) {
                return $maybe_id;
            }
        }

        return 0;
    }

    /**
     * Checks the database for a listing with the exact same title and start time.
     */
    public function has_duplicate_event_title_start($title, $start) {
        return $this->find_duplicate_event_candidate($title, $start, '', '', '', 0) > 0;
    }

    /**
     * Normalizes an array row, trimming spaces from strings.
     */
    public function normalize_import_row($row) {
        $normalized = [];
        foreach ((array) $row as $key => $value) {
            $k = sanitize_key((string) $key);
            if ($k === '') continue;
            $normalized[$k] = is_string($value) ? trim($value) : $value;
        }
        return $normalized;
    }

    /**
     * Core insertion function: creates the WP_Post and attaches all sanitized meta/taxonomies.
     */
    public function import_event_from_row($row, $default_status = 'pending', $skip_duplicates = false, $author_id = 0, $enforce_demo_limit = true) {
        $row = $this->normalize_import_row($row);
        $extra_fields_raw = $row['extra_fields'] ?? [];
        if (is_string($extra_fields_raw)) {
            $decoded_extra_fields = json_decode($extra_fields_raw, true);
            $extra_fields_raw = is_array($decoded_extra_fields) ? $decoded_extra_fields : [];
        }
        if (is_array($extra_fields_raw) && !empty($extra_fields_raw)) {
            foreach ($extra_fields_raw as $extra_key => $extra_value) {
                $extra_key = sanitize_key((string) $extra_key);
                if ($extra_key === '' || (strpos($extra_key, 'nexdirectory_') !== 0 && strpos($extra_key, 'nexdirectory_tax_') !== 0)) {
                    continue;
                }
                if (!array_key_exists($extra_key, $row)) {
                    $row[$extra_key] = $extra_value;
                }
            }
        }
        $title = sanitize_text_field((string) ($row['title'] ?? $row['post_title'] ?? ''));
        if ($title === '') {
            return new WP_Error('missing_title', __('Missing required title.', 'nexdirectory'));
        }

        $start_value = $this->date_helper->normalize_datetime_local((string) ($row['start'] ?? ''));
        $end_value = $this->date_helper->normalize_datetime_local((string) ($row['end'] ?? ''));
        $duplicate_detection_enabled = (string) get_option('nexdirectory_enable_duplicate_detection', '1') === '1';
        $duplicate_candidate_id = 0;
        if ($duplicate_detection_enabled || $skip_duplicates) {
            $duplicate_candidate_id = $this->find_duplicate_event_candidate(
                $title,
                $start_value,
                (string) ($row['city'] ?? ''),
                (string) ($row['address'] ?? ''),
                (string) ($row['venue'] ?? ''),
                0
            );
        }
        if ($skip_duplicates && $duplicate_candidate_id > 0) {
            return new WP_Error(
                'duplicate_event',
                __('Duplicate row skipped (same title, date/time, and location already exists).', 'nexdirectory'),
                ['duplicate_post_id' => $duplicate_candidate_id]
            );
        }

        $allowed_statuses = ['pending', 'draft', 'publish'];
        $status = sanitize_key((string) ($row['status'] ?? $default_status));
        if (!in_array($status, $allowed_statuses, true)) {
            $status = $default_status;
        }
        
        $author_id = $this->get_default_import_author_id($author_id);
        $post_id = wp_insert_post([
            'post_type' => $this->post_type,
            'post_status' => $status,
            'post_author' => $author_id,
            'post_title' => $title,
            'post_content' => wp_kses_post((string) ($row['description'] ?? $row['content'] ?? '')),
            'post_excerpt' => nexdirectory_sanitize_textarea((string) ($row['excerpt'] ?? '')),
        ], true);

        if (is_wp_error($post_id)) {
            return $post_id;
        }

        if ($duplicate_detection_enabled && $duplicate_candidate_id > 0) {
            update_post_meta($post_id, 'nexdirectory_duplicate_candidate', (string) $duplicate_candidate_id);
        } else {
            delete_post_meta($post_id, 'nexdirectory_duplicate_candidate');
        }

        // Delegate specific meta cleanups to the Meta Service
        $meta_map = [
            'nexdirectory_start' => $start_value,
            'nexdirectory_end' => $end_value,
            'nexdirectory_meta_title' => (string) ($row['meta_title'] ?? ''),
            'nexdirectory_meta_description' => (string) ($row['meta_description'] ?? ''),
            'nexdirectory_timezone' => (string) ($row['timezone'] ?? ''),
            'nexdirectory_venue' => (string) ($row['venue'] ?? ''),
            'nexdirectory_company_name' => (string) ($row['company_name'] ?? ''),
            'nexdirectory_address' => (string) ($row['address'] ?? ''),
            'nexdirectory_city' => (string) ($row['city'] ?? ''),
            'nexdirectory_country' => (string) ($row['country'] ?? ''),
            'nexdirectory_lat' => (string) ($row['lat'] ?? ''),
            'nexdirectory_lng' => (string) ($row['lng'] ?? ''),
            'nexdirectory_capacity' => (string) ($row['capacity'] ?? ''),
            'nexdirectory_price' => (string) ($row['price'] ?? ''),
            'nexdirectory_ticket_sales_enabled' => (string) ($row['ticket_sales_enabled'] ?? '0'),
            'nexdirectory_ticket_price' => (string) ($row['ticket_price'] ?? ''),
            'nexdirectory_ticket_button_label' => (string) ($row['ticket_button_label'] ?? ''),
            'nexdirectory_external_url' => (string) ($row['external_url'] ?? $row['website'] ?? ''),
            'nexdirectory_event_stream_url' => (string) ($row['stream_url'] ?? $row['video_stream_url'] ?? ''),
            'nexdirectory_contact_email' => (string) ($row['contact_email'] ?? ''),
            'nexdirectory_contact_phone' => (string) ($row['contact_phone'] ?? ''),
            'nexdirectory_contact_name' => (string) ($row['contact_name'] ?? ''),
            'nexdirectory_cover_image_url' => (string) ($row['cover_image_url'] ?? ''),
            'nexdirectory_supporting_docs' => (string) ($row['supporting_docs_urls'] ?? $row['supporting_docs'] ?? ''),
            'nexdirectory_official_event' => $this->event_meta->normalize_official_event_value($row['official_event'] ?? '0'),
            'nexdirectory_recurrence' => (string) ($row['recurrence'] ?? 'none'),
            'nexdirectory_recurrence_until' => (string) ($row['recurrence_until'] ?? ''),
            'nexdirectory_job_type' => (string) ($row['job_type'] ?? ''),
            'nexdirectory_job_work_mode' => (string) ($row['job_work_mode'] ?? ''),
            'nexdirectory_job_salary' => (string) ($row['job_salary'] ?? ''),
            'nexdirectory_job_apply_url' => (string) ($row['job_apply_url'] ?? ''),
            'nexdirectory_job_application_email' => (string) ($row['job_application_email'] ?? ''),
            'nexdirectory_job_closing_date' => (string) ($row['job_closing_date'] ?? ''),
            'nexdirectory_job_department' => (string) ($row['job_department'] ?? ''),
        ];

        foreach ($meta_map as $meta_key => $raw_value) {
            update_post_meta($post_id, $meta_key, $this->event_meta->sanitize_meta_value($meta_key, $raw_value));
        }
        $event_meta_fields = method_exists($this->event_meta, 'get_event_meta_fields')
            ? (array) $this->event_meta->get_event_meta_fields()
            : [];
        foreach ($event_meta_fields as $meta_key => $unused_meta_type) {
            $meta_key = sanitize_key((string) $meta_key);
            if ($meta_key === '' || isset($meta_map[$meta_key]) || !array_key_exists($meta_key, $row)) {
                continue;
            }
            update_post_meta($post_id, $meta_key, $this->event_meta->sanitize_meta_value($meta_key, $row[$meta_key]));
        }
        $ignored_extension_meta_keys = array_fill_keys([
            'nexdirectory_nonce',
            'nexdirectory_website',
            'nexdirectory_recaptcha_token',
            'nexdirectory_autosave_post_id',
            'nexdirectory_edit_post_id',
            'nexdirectory_custom_fields_builder_json',
            'nexdirectory_cover_file',
            'nexdirectory_gallery_files',
            'nexdirectory_intent',
        ], true);
        foreach ($row as $row_key => $row_value) {
            $row_key = sanitize_key((string) $row_key);
            if ($row_key === '' || strpos($row_key, 'nexdirectory_') !== 0 || strpos($row_key, 'nexdirectory_tax_') === 0) {
                continue;
            }
            if (isset($meta_map[$row_key]) || isset($event_meta_fields[$row_key]) || isset($ignored_extension_meta_keys[$row_key])) {
                continue;
            }
            if (is_string($row_value) && trim($row_value) === '') {
                continue;
            }
            update_post_meta($post_id, $row_key, $this->event_meta->sanitize_meta_value($row_key, $row_value));
        }
        if ($start_value !== '') {
            update_post_meta($post_id, 'start', $start_value);
            update_post_meta($post_id, 'event_start', $start_value);
            update_post_meta($post_id, 'nexdirectory_start_raw', $start_value);
        }
        if ($end_value !== '') {
            update_post_meta($post_id, 'end', $end_value);
            update_post_meta($post_id, 'event_end', $end_value);
            update_post_meta($post_id, 'nexdirectory_end_raw', $end_value);
        }

        $video_raw = (string) ($row['video_urls'] ?? $row['videos'] ?? '');
        $gallery_raw = (string) ($row['gallery_urls'] ?? $row['gallery'] ?? '');
        if (is_object($this->event_meta) && method_exists($this->event_meta, 'update_media_meta')) {
            $this->event_meta->update_media_meta($post_id, $video_raw, $gallery_raw);
        } else {
            update_post_meta($post_id, 'nexdirectory_video_urls', nexdirectory_sanitize_textarea($video_raw));
            update_post_meta($post_id, 'nexdirectory_gallery_urls', nexdirectory_sanitize_textarea($gallery_raw));
        }
        
        $sessions_source = $row['sessions']
            ?? $row['sessions_json']
            ?? $row['itinerary']
            ?? $row['itinerary_json']
            ?? $row['agenda']
            ?? $row['timeline']
            ?? $row['day_of_action']
            ?? $row['a_day_of_action']
            ?? [];
        if (is_array($sessions_source)) {
            $sessions_source = wp_json_encode($sessions_source);
        }

        $key_speakers_source = $row['key_speakers']
            ?? $row['key_speakers_json']
            ?? $row['key_speaker']
            ?? $row['keyspeaker']
            ?? $row['speakers']
            ?? $row['speakers_json']
            ?? $row['speaker_profiles']
            ?? $row['speaker_profiles_json']
            ?? $row['speaker']
            ?? [];
        if (is_array($key_speakers_source)) {
            $key_speakers_source = wp_json_encode($key_speakers_source);
        }

        update_post_meta($post_id, 'nexdirectory_sessions', wp_json_encode($this->event_meta->parse_sessions((string) $sessions_source)));
        update_post_meta($post_id, 'nexdirectory_key_speakers', wp_json_encode($this->event_meta->parse_key_speakers((string) $key_speakers_source)));

        $custom_fields_raw = $row['custom_fields'] ?? ($row['custom_field_values'] ?? ($row['nexdirectory_custom_fields_data'] ?? []));
        if (is_string($custom_fields_raw)) {
            $decoded_custom_fields = json_decode($custom_fields_raw, true);
            $custom_fields_raw = is_array($decoded_custom_fields) ? $decoded_custom_fields : [];
        }
        if (is_array($custom_fields_raw) && !empty($custom_fields_raw)) {
            $schema_raw = $row['custom_fields_schema'] ?? ($row['nexdirectory_custom_fields_schema'] ?? []);
            if (is_string($schema_raw)) {
                $decoded_schema = json_decode($schema_raw, true);
                $schema_raw = is_array($decoded_schema) ? $decoded_schema : [];
            }
            do_action(
                'nexdirectory_persist_import_custom_fields',
                $post_id,
                $custom_fields_raw,
                is_array($schema_raw) ? $schema_raw : [],
                $this
            );
        }

        // Delegate taxonomy assignment
        $this->taxonomy_service->set_terms_from_values($post_id, 'event_type', $row['event_type'] ?? $row['type'] ?? ($row['job_department'] ?? ($row['job_type'] ?? '')));
        $this->taxonomy_service->set_terms_from_values($post_id, 'event_mode', $row['event_mode'] ?? $row['mode'] ?? ($row['job_work_mode'] ?? ''));
        $this->taxonomy_service->set_terms_from_values($post_id, 'event_price_range', $row['event_price_range'] ?? $row['price_range'] ?? '');
        $this->taxonomy_service->set_terms_from_values($post_id, 'event_tag', $row['event_tags'] ?? $row['tags'] ?? ($row['job_skills'] ?? ''));
        foreach ($row as $row_key => $row_value) {
            $row_key = sanitize_key((string) $row_key);
            if (strpos($row_key, 'nexdirectory_tax_') !== 0) {
                continue;
            }
            $taxonomy_slug = sanitize_key((string) substr($row_key, 8));
            if ($taxonomy_slug === '' || !taxonomy_exists($taxonomy_slug)) {
                continue;
            }
            $this->taxonomy_service->set_terms_from_values($post_id, $taxonomy_slug, $row_value);
        }

        return $post_id;
    }
}
