<?php
// includes/form-renderer.php
// Note: JS (`assets/form.js`) may render fields on the client.
// This PHP is a lean fallback (SSR) if JS is disabled (or for initial markup).

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

function afb_render_dynamic_fields($fields_raw, $cfg) {
    $used_fields        = $cfg['used_fields'] ?? [];
    $required_fields    = $cfg['required_fields'] ?? [];
    $hidden_fields      = $cfg['hidden_fields'] ?? [];
    $readonly_fields    = $cfg['readonly_fields'] ?? [];
    $paragraph_fields   = $cfg['paragraph_fields'] ?? [];
    $labels             = $cfg['labels'] ?? [];
    $descriptions       = $cfg['descriptions'] ?? [];
    $field_order_raw    = $cfg['field_order'] ?? [];
    $custom_paragraphs  = $cfg['custom_paragraphs'] ?? [];
    $paragraph_titles   = $cfg['custom_paragraph_titles'] ?? [];
    $custom_sections    = $cfg['custom_sections'] ?? [];
    $section_titles     = $cfg['custom_section_titles'] ?? [];
    $agreement_labels   = $cfg['custom_agreement_labels'] ?? [];
    $agreement_details  = $cfg['custom_agreement_details'] ?? [];
    $agreement_required_configured = array_key_exists('agreement_required_fields', $cfg);
    $agreement_required_fields = ($agreement_required_configured && is_array($cfg['agreement_required_fields']))
        ? $cfg['agreement_required_fields']
        : [];
    $upload_titles      = $cfg['custom_upload_titles'] ?? [];
    $upload_details     = $cfg['custom_upload_details'] ?? [];
    $upload_min_files   = $cfg['custom_upload_min_files'] ?? [];
    $upload_accept_types = is_array($cfg['custom_upload_accept_types'] ?? null)
        ? $cfg['custom_upload_accept_types']
        : [];
    $upload_compress_images_raw = is_array($cfg['custom_upload_compress_images'] ?? null)
        ? $cfg['custom_upload_compress_images']
        : [];
    $upload_compress_images = [];
    foreach ($upload_compress_images_raw as $key => $value) {
        if (is_string($value) && $value !== '') {
            $upload_compress_images[] = $value;
            continue;
        }

        if (is_string($key) && $key !== '' && !is_int($key)) {
            $upload_compress_images[] = $key;
        }
    }
    $upload_compress_images = array_values(array_unique($upload_compress_images));
    $upload_compress_images_configured = array_key_exists('custom_upload_compress_images', $cfg);
    $upload_max_file_mb_raw = is_array($cfg['custom_upload_max_file_mb'] ?? null)
        ? $cfg['custom_upload_max_file_mb']
        : [];
    $upload_max_file_mb = [];
    foreach ($upload_max_file_mb_raw as $upload_id_raw => $max_file_mb_raw) {
        $upload_id = sanitize_text_field((string) $upload_id_raw);
        if ($upload_id === '' || strpos($upload_id, 'upload_') !== 0) {
            continue;
        }

        $max_file_mb = (float) $max_file_mb_raw;
        if ($max_file_mb <= 0) {
            continue;
        }

        $upload_max_file_mb[$upload_id] = min(512, round($max_file_mb, 2));
    }
    $upload_max_width_px_raw = is_array($cfg['custom_upload_max_width_px'] ?? null)
        ? $cfg['custom_upload_max_width_px']
        : [];
    $upload_max_width_px = [];
    foreach ($upload_max_width_px_raw as $upload_id_raw => $max_width_raw) {
        $upload_id = sanitize_text_field((string) $upload_id_raw);
        if ($upload_id === '' || strpos($upload_id, 'upload_') !== 0) {
            continue;
        }

        $max_width = (int) round((float) $max_width_raw);
        if ($max_width <= 0) {
            continue;
        }

        $upload_max_width_px[$upload_id] = max(100, min(4000, $max_width));
    }
    $upload_compress_quality_raw = is_array($cfg['custom_upload_compress_quality'] ?? null)
        ? $cfg['custom_upload_compress_quality']
        : [];
    $upload_compress_quality = [];
    foreach ($upload_compress_quality_raw as $upload_id_raw => $quality_raw) {
        $upload_id = sanitize_text_field((string) $upload_id_raw);
        if ($upload_id === '' || strpos($upload_id, 'upload_') !== 0) {
            continue;
        }

        $quality = (float) $quality_raw;
        if ($quality <= 0) {
            continue;
        }

        $upload_compress_quality[$upload_id] = max(1, min(100, (int) round($quality)));
    }
    $single_input_labels = $cfg['custom_single_input_labels'] ?? [];
    $single_input_descriptions = $cfg['custom_single_input_descriptions'] ?? [];
    $single_input_placeholders = $cfg['custom_single_input_placeholders'] ?? [];
    $single_input_sync_fields = $cfg['custom_single_input_sync_fields'] ?? [];
    $single_input_modes = $cfg['custom_single_input_modes'] ?? [];
    $single_input_max_words_enabled = $cfg['custom_single_input_max_words_enabled'] ?? [];
    $single_input_max_words = $cfg['custom_single_input_max_words'] ?? [];
    $single_input_ai_enabled = $cfg['custom_single_input_ai_enabled'] ?? [];
    $dropdown_labels   = $cfg['custom_dropdown_labels'] ?? [];
    $dropdown_descriptions = $cfg['custom_dropdown_descriptions'] ?? [];
    $dropdown_placeholders = $cfg['custom_dropdown_placeholders'] ?? [];
    $dropdown_options = $cfg['custom_dropdown_options'] ?? [];
    $dropdown_selection_modes = $cfg['custom_dropdown_selection_modes'] ?? [];
    $dropdown_sync_fields = $cfg['custom_dropdown_sync_fields'] ?? [];
    $calendar_labels   = $cfg['custom_calendar_labels'] ?? [];
    $calendar_descriptions = $cfg['custom_calendar_descriptions'] ?? [];
    $calendar_placeholders = $cfg['custom_calendar_placeholders'] ?? [];
    $calendar_sync_modes = $cfg['custom_calendar_sync_modes'] ?? [];
    $calendar_sync_fields = $cfg['custom_calendar_sync_fields'] ?? [];
    $text_sync_fields = $cfg['custom_text_sync_fields'] ?? [];
    $calendar_preset_modes = $cfg['custom_calendar_preset_modes'] ?? [];
    $calendar_preset_options = $cfg['custom_calendar_preset_options'] ?? [];
    $visible_enum_options = $cfg['visible_enum_options'] ?? [];
    $allow_uploads      = !empty($cfg['allow_uploads']);
    $custom_sections    = $cfg['custom_sections'] ?? [];
    $section_titles     = $cfg['custom_section_titles'] ?? [];

    $field_order = [];
    if (is_array($field_order_raw)) {
        foreach ($field_order_raw as $key => $value) {
            if (is_string($value) && $value !== '') {
                $field_order[] = $value;
                continue;
            }
            if (is_string($key) && $key !== '' && !is_int($key)) {
                $field_order[] = $key;
            }
        }
    }

    if (empty($field_order)) {
        $field_order = array_values(array_unique(array_filter(array_merge(
            array_keys((array) $paragraph_titles),
            array_keys((array) $section_titles),
            array_keys((array) $agreement_labels),
            array_keys((array) $upload_titles),
            array_keys((array) $single_input_labels),
            array_keys((array) $dropdown_labels),
            array_keys((array) $calendar_labels),
            array_map('strval', (array) $used_fields)
        ), static function ($id) {
            return is_string($id) && $id !== '';
        })));
    }

    // Legacy migration: old configs used allow_uploads without upload_* order entries.
    // Normalize to a regular upload block so rendering uses one upload model.
    $has_upload_block = false;
    foreach ((array) $field_order as $ordered_id) {
        if (strpos((string) $ordered_id, 'upload_') === 0) {
            $has_upload_block = true;
            break;
        }
    }

    if ($allow_uploads && !$has_upload_block) {
        $legacy_upload_id = 'upload_legacy_optional';
        $legacy_suffix = 1;
        while (in_array($legacy_upload_id, $field_order, true)) {
            $legacy_upload_id = 'upload_legacy_optional_' . $legacy_suffix;
            $legacy_suffix++;
        }

        $field_order[] = $legacy_upload_id;

        if (!isset($upload_titles[$legacy_upload_id]) || trim((string) $upload_titles[$legacy_upload_id]) === '') {
            $upload_titles[$legacy_upload_id] = 'File Uploads';
        }
        if (!isset($upload_details[$legacy_upload_id]) || trim((string) $upload_details[$legacy_upload_id]) === '') {
            $upload_details[$legacy_upload_id] = 'Please upload any relevant documents to this request. We have a maximum upload size of 64MB.';
        }
        if (!isset($upload_min_files[$legacy_upload_id])) {
            $upload_min_files[$legacy_upload_id] = 0;
        }
    }

    // ✅ NEW: half-width fields (50%)
    $half_width_fields  = $cfg['half_width_fields'] ?? [];

    // gid => field meta
    $field_map = [];
    foreach ((array)$fields_raw as $setting) {
        if (!isset($setting['custom_field'])) continue;
        $f = $setting['custom_field'];
        if (!isset($f['gid'])) continue;
        $field_map[(string)$f['gid']] = $f;
    }

    // ✅ Layout wrapper (flex 2-col on md+, stacked on mobile)
    echo '<div class="afb-fields flex flex-wrap gap-2">';

    foreach ((array)$field_order as $id) {
        $id = (string)$id;

        // Paragraph block (always full width)
        if (strpos($id, 'para_') === 0) {
            $text  = $custom_paragraphs[$id] ?? '';
            $title = $paragraph_titles[$id] ?? '';

            if (trim((string)$text) !== '') {
                echo '<div class="w-full">';
                echo '<div data-field-id="' . esc_attr($id) . '" class="afb-paragraph-block">';
                if ($title) {
                    echo '<h3>' . esc_html($title) . '</h3>';
                }
                echo '<div class="afb-paragraph-content">' . wpautop(wp_kses_post($text)) . '</div>';
                echo '</div>';
                echo '</div>';
            }
            continue;
        }

        // Section break block (fallback if JS step wizard is unavailable)
        if (strpos($id, 'section_') === 0) {
            $title = trim((string)($section_titles[$id] ?? ''));
            $text  = trim((string)($custom_sections[$id] ?? ''));

            if ($title !== '' || $text !== '') {
                echo '<div class="w-full">';
                echo '<div class="afb-step-intro" data-field-id="' . esc_attr($id) . '">';
                if ($title !== '') {
                    echo '<h3 class="afb-step-title">' . esc_html($title) . '</h3>';
                }
                if ($text !== '') {
                    echo '<p class="afb-step-desc">' . esc_html($text) . '</p>';
                }
                echo '</div>';
                echo '</div>';
            }
            continue;
        }

        // Agreement checkbox block (required, local-only, not mapped to Asana custom fields)
        if (strpos($id, 'agree_') === 0) {
            $agreement_label = trim((string)($agreement_labels[$id] ?? 'I agree'));
            $agreement_text  = trim((string)($agreement_details[$id] ?? ''));
            $agreement_is_required = $agreement_required_configured
                ? in_array($id, $agreement_required_fields, true)
                : true;
            $agreement_required_attr = $agreement_is_required ? ' required' : '';

            echo '<div class="w-full" data-field-id="' . esc_attr($id) . '">';
            echo '<label class="inline-flex items-start gap-2 text-gray-700">';
            echo '<input type="checkbox" name="agreement_checks[' . esc_attr($id) . ']" value="1"' . $agreement_required_attr . ' data-afb-agreement="1" class="mt-1 rounded border-gray-300">';
            echo '<span>' . esc_html($agreement_label !== '' ? $agreement_label : 'I agree') . '</span>';
            echo '</label>';
            if ($agreement_text !== '') {
                echo '<p class="text-sm text-gray-500 mt-1 mb-0">' . esc_html($agreement_text) . '</p>';
            }
            echo '</div>';
            continue;
        }

        if (strpos($id, 'upload_') === 0) {
            $upload_title = trim((string)($upload_titles[$id] ?? 'Upload Area'));
            $upload_text  = trim((string)($upload_details[$id] ?? ''));
            $min_files    = max(0, (int)($upload_min_files[$id] ?? 0));
            $upload_accept_raw = sanitize_text_field((string)($upload_accept_types[$id] ?? ''));
            $compress_images = $upload_compress_images_configured
                ? in_array($id, $upload_compress_images, true)
                : true;
            $max_file_mb = max(0.0, (float)($upload_max_file_mb[$id] ?? 0));
            $compress_max_width = max(100, min(4000, (int)($upload_max_width_px[$id] ?? 1200)));
            $compress_quality = max(1, min(100, (int)($upload_compress_quality[$id] ?? 60)));
            $max_file_mb_label = $max_file_mb > 0
                ? rtrim(rtrim(number_format($max_file_mb, 2, '.', ''), '0'), '.')
                : '';
            $upload_accept_tokens = [];
            if ($upload_accept_raw !== '') {
                $accept_parts = preg_split('/\s*,\s*/', strtolower($upload_accept_raw));
                if (is_array($accept_parts)) {
                    foreach ($accept_parts as $accept_part) {
                        $accept_token = trim((string) $accept_part);
                        if ($accept_token === '') {
                            continue;
                        }

                        $accept_token = preg_replace('/\s+/', '', $accept_token);
                        if ($accept_token === '') {
                            continue;
                        }

                        if (strpos($accept_token, '.') === 0) {
                            $ext = preg_replace('/[^a-z0-9]/', '', substr($accept_token, 1));
                            if ($ext === '') {
                                continue;
                            }

                            $accept_token = '.' . $ext;
                        } elseif (preg_match('/^[a-z0-9!#$&^_.+-]+\/(?:[a-z0-9!#$&^_.+-]+|\*)$/', $accept_token)) {
                            // Valid MIME token.
                        } elseif (preg_match('/^[a-z0-9]{1,16}$/', $accept_token)) {
                            $accept_token = '.' . $accept_token;
                        } else {
                            continue;
                        }

                        $upload_accept_tokens[$accept_token] = true;
                    }
                }
            }

            $upload_accept_value = '';
            if (!empty($upload_accept_tokens)) {
                $upload_accept_value = implode(',', array_keys($upload_accept_tokens));
            }

            $required_badge = '';
            if ($min_files > 0) {
                $required_badge = $min_files > 1
                    ? 'Required: ' . $min_files . '+'
                    : 'Required';
            }

            echo '<div class="w-full" data-field-id="' . esc_attr($id) . '">';
            echo '<div class="afb-upload-block" data-field-id="' . esc_attr($id) . '" data-min-files="' . esc_attr((string) $min_files) . '"';
            if ($upload_accept_value !== '') {
                echo ' data-accept-types="' . esc_attr($upload_accept_value) . '"';
            }
            echo ' data-compress-images="' . ($compress_images ? '1' : '0') . '"';
            echo ' data-compress-max-width="' . esc_attr((string) $compress_max_width) . '"';
            echo ' data-compress-quality="' . esc_attr((string) $compress_quality) . '"';
            if ($max_file_mb > 0) {
                echo ' data-max-file-mb="' . esc_attr($max_file_mb_label) . '"';
            }
            echo '>';
            echo '<div class="afb-upload-block-inner">';
            echo '<div class="afb-upload-header flex items-start justify-between gap-3">';
            echo '<div class="min-w-0">';
            echo '<p class="afb-upload-heading font-semibold text-gray-700 mb-1">' . esc_html($upload_title !== '' ? $upload_title : 'Upload Area') . '</p>';
            if ($upload_text !== '') {
                echo '<p class="text-sm text-gray-600 mb-0">' . esc_html($upload_text) . '</p>';
            }
            if ($upload_accept_value !== '') {
                echo '<p class="text-xs text-gray-500 mb-0 mt-1">Accepted file types: ' . esc_html(str_replace(',', ', ', $upload_accept_value)) . '</p>';
            }
            if ($compress_images) {
                echo '<p class="text-xs text-gray-500 mb-0 mt-1">Images are compressed automatically on upload (max ' . esc_html((string) $compress_max_width) . 'px wide, ~' . esc_html((string) $compress_quality) . '% quality).</p>';
            }
            if ($max_file_mb > 0) {
                echo '<p class="text-xs text-gray-500 mb-0 mt-1">Max file size per file: ' . esc_html($max_file_mb_label) . ' MB</p>';
            }
            echo '</div>';
            if ($required_badge !== '') {
                echo '<span class="afb-upload-required-badge text-xs font-semibold uppercase tracking-wide whitespace-nowrap">' . esc_html($required_badge) . '</span>';
            }
            echo '</div>';
            echo '<div class="upload-fields mt-3 space-y-2">';
            echo '<div class="file-list space-y-2"></div>';
            echo '<button type="button" class="add-file-btn bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600">+ Add File</button>';
            echo '</div>';
            echo '</div>';
            echo '</div>';
            echo '</div>';
            continue;
        }

        if (strpos($id, 'single_') === 0) {
            $single_label = trim((string)($single_input_labels[$id] ?? 'Additional detail'));
            $single_text = trim((string)($single_input_descriptions[$id] ?? ''));
            $single_placeholder = trim((string)($single_input_placeholders[$id] ?? ''));
            $single_sync_gid = trim((string)($single_input_sync_fields[$id] ?? ''));
            $single_mode_raw = trim((string)($single_input_modes[$id] ?? 'text'));
            $single_mode = in_array($single_mode_raw, ['text', 'textarea'], true) ? $single_mode_raw : 'text';
            $single_max_words_enabled = in_array($id, (array) $single_input_max_words_enabled, true);
            $single_max_words = max(0, (int) ($single_input_max_words[$id] ?? 0));
            $single_ai_enabled = in_array($id, (array) $single_input_ai_enabled, true);
            $single_word_limit_attr = ($single_mode === 'textarea' && $single_max_words_enabled && $single_max_words > 0)
                ? ' data-afb-max-words="' . esc_attr((string) $single_max_words) . '"'
                : '';
            $single_container_class = in_array($id, $half_width_fields, true) ? 'w-full md:w-1/2' : 'w-full';

            echo '<div class="' . esc_attr($single_container_class) . '">';
            echo '<label class="block mb-2" data-field-id="' . esc_attr($id) . '">';
            echo '<span class="text-gray-700">' . esc_html($single_label !== '' ? $single_label : 'Additional detail') . '</span>';
            if ($single_text !== '') {
                echo '<p class="text-sm text-gray-500 mb-2">' . esc_html($single_text) . '</p>';
            }

            if ($single_mode === 'textarea') {
                if ($single_sync_gid !== '') {
                    echo '<textarea rows="1" class="mt-1 block w-full afb-single-input-textarea" data-afb-sync-target="' . esc_attr($single_sync_gid) . '" placeholder="' . esc_attr($single_placeholder) . '"' . $single_word_limit_attr . '></textarea>';
                } else {
                    echo '<textarea name="description_inputs[' . esc_attr($id) . ']" class="mt-1 block w-full afb-single-input-textarea" data-afb-description-input="1" data-afb-description-id="' . esc_attr($id) . '" data-afb-description-label="' . esc_attr($single_label) . '" placeholder="' . esc_attr($single_placeholder) . '"' . $single_word_limit_attr . '></textarea>';
                }
            } else {
                if ($single_sync_gid !== '') {
                    echo '<input type="text" class="mt-1 block w-full" data-afb-sync-target="' . esc_attr($single_sync_gid) . '" placeholder="' . esc_attr($single_placeholder) . '">';
                } else {
                    echo '<input type="text" name="description_inputs[' . esc_attr($id) . ']" class="mt-1 block w-full" data-afb-description-input="1" data-afb-description-id="' . esc_attr($id) . '" data-afb-description-label="' . esc_attr($single_label) . '" placeholder="' . esc_attr($single_placeholder) . '">';
                }
            }

            if ($single_mode === 'textarea' && $single_max_words_enabled && $single_max_words > 0) {
                echo '<p class="mt-1 text-xs text-slate-500 afb-single-word-limit" aria-live="polite"></p>';
            }

            if ($single_ai_enabled) {
                echo '<div class="afb-single-ai-helper mt-2">';
                echo '<div class="afb-single-ai-head">';
                echo '<span class="afb-single-ai-badge">AI help</span>';
                echo '<div class="afb-single-ai-controls">';
                echo '<select class="afb-single-ai-preset" data-afb-ai-preset="1" aria-label="Rewrite style">';
                echo '<option value="improve" selected>Improve clarity</option>';
                echo '<option value="shorter">Make it shorter</option>';
                echo '<option value="formal">More formal</option>';
                echo '<option value="friendly">Friendlier</option>';
                echo '<option value="plain">Plain English</option>';
                echo '</select>';
                echo '<button type="button" class="afb-single-ai-btn" data-afb-ai-rewrite="1" data-afb-ai-mode="' . esc_attr($single_mode) . '"';
                if ($single_mode === 'textarea' && $single_max_words_enabled && $single_max_words > 0) {
                    echo ' data-afb-ai-max-words="' . esc_attr((string) $single_max_words) . '"';
                }
                echo '>Rewrite with AI</button>';
                echo '</div>';
                echo '</div>';
                echo '<p class="afb-single-ai-note text-xs text-slate-500 mt-1 mb-0">Use AI to improve wording while keeping your meaning.</p>';
                echo '</div>';
            }

            echo '</label>';
            echo '</div>';
            continue;
        }

        if (strpos($id, 'dropdown_') === 0) {
            $dropdown_label = trim((string)($dropdown_labels[$id] ?? 'Choose an option'));
            $dropdown_text = trim((string)($dropdown_descriptions[$id] ?? ''));
            $dropdown_placeholder = trim((string)($dropdown_placeholders[$id] ?? '-- Select --'));
            $dropdown_sync_gid = trim((string)($dropdown_sync_fields[$id] ?? ''));
            $dropdown_selection_mode_raw = trim((string)($dropdown_selection_modes[$id] ?? 'single'));
            $dropdown_selection_mode = in_array($dropdown_selection_mode_raw, ['single', 'multi'], true)
                ? $dropdown_selection_mode_raw
                : 'single';
            $dropdown_is_required = in_array($id, $required_fields, true);
            $dropdown_container_class = in_array($id, $half_width_fields, true) ? 'w-full md:w-1/2' : 'w-full';
            $dropdown_lines = preg_split('/\r\n|\r|\n/', (string)($dropdown_options[$id] ?? ''));
            $dropdown_lines = is_array($dropdown_lines) ? $dropdown_lines : [];

            echo '<div class="' . esc_attr($dropdown_container_class) . '">';
            echo '<label class="block mb-2" data-field-id="' . esc_attr($id) . '">';
            echo '<span class="text-gray-700">' . esc_html($dropdown_label !== '' ? $dropdown_label : 'Choose an option') . ($dropdown_is_required ? ' <span class="text-red-500">*</span>' : '') . '</span>';
            if ($dropdown_text !== '') {
                echo '<p class="text-sm text-gray-500 mb-2">' . esc_html($dropdown_text) . '</p>';
            }

            if ($dropdown_selection_mode === 'multi') {
                echo '<div class="mt-2 flex flex-col gap-2" data-multienum="1"';
                if ($dropdown_is_required) {
                    echo ' data-required="1"';
                }
                if ($dropdown_sync_gid !== '') {
                    echo ' data-afb-sync-target-group="' . esc_attr($dropdown_sync_gid) . '"';
                } else {
                    echo ' data-afb-description-group="1" data-afb-description-id="' . esc_attr($id) . '" data-afb-description-label="' . esc_attr($dropdown_label) . '"';
                }
                echo '>';

                foreach ($dropdown_lines as $dropdown_line) {
                    $option_text = trim((string) $dropdown_line);
                    if ($option_text === '') {
                        continue;
                    }

                    echo '<label class="inline-flex items-center space-x-2">';
                    echo '<input type="checkbox" value="' . esc_attr($option_text) . '" class="rounded border-gray-300">';
                    echo '<span>' . esc_html($option_text) . '</span>';
                    echo '</label>';
                }

                echo '</div>';
            } else {
                $dropdown_required_attr = $dropdown_is_required ? ' required' : '';

                if ($dropdown_sync_gid !== '') {
                    echo '<select class="mt-1 block w-full" data-afb-sync-target="' . esc_attr($dropdown_sync_gid) . '"' . $dropdown_required_attr . '>';
                } else {
                    echo '<select name="description_inputs[' . esc_attr($id) . ']" class="mt-1 block w-full" data-afb-description-input="1" data-afb-description-id="' . esc_attr($id) . '" data-afb-description-label="' . esc_attr($dropdown_label) . '"' . $dropdown_required_attr . '>';
                }

                echo '<option value="">' . esc_html($dropdown_placeholder !== '' ? $dropdown_placeholder : '-- Select --') . '</option>';
                foreach ($dropdown_lines as $dropdown_line) {
                    $option_text = trim((string) $dropdown_line);
                    if ($option_text === '') {
                        continue;
                    }
                    echo '<option value="' . esc_attr($option_text) . '">' . esc_html($option_text) . '</option>';
                }
                echo '</select>';
            }

            echo '</label>';
            echo '</div>';
            continue;
        }

        if (strpos($id, 'calendar_') === 0) {
            $calendar_label = trim((string)($calendar_labels[$id] ?? 'Select a date'));
            $calendar_text = trim((string)($calendar_descriptions[$id] ?? ''));
            $calendar_placeholder = trim((string)($calendar_placeholders[$id] ?? '-- Select a date --'));
            $calendar_sync_mode_raw = trim((string)($calendar_sync_modes[$id] ?? 'text'));
            $calendar_sync_gid = trim((string)($calendar_sync_fields[$id] ?? ''));
            $calendar_sync_mode = in_array($calendar_sync_mode_raw, ['none', 'text', 'due_date'], true)
                ? $calendar_sync_mode_raw
                : ($calendar_sync_gid !== '' ? 'text' : 'none');
            $calendar_is_required = in_array($id, $required_fields, true);
            $calendar_container_class = in_array($id, $half_width_fields, true) ? 'w-full md:w-1/2' : 'w-full';
            $calendar_preset_mode = trim((string)($calendar_preset_modes[$id] ?? 'none'));
            $calendar_option_rows = [];
            if ($calendar_preset_mode === 'ealert_next_4_wednesdays') {
                $calendar_option_rows = is_array($calendar_preset_options[$id] ?? null)
                    ? $calendar_preset_options[$id]
                    : [];
            }

            echo '<div class="' . esc_attr($calendar_container_class) . '">';
            echo '<label class="block mb-2" data-field-id="' . esc_attr($id) . '">';
            echo '<span class="text-gray-700">' . esc_html($calendar_label !== '' ? $calendar_label : 'Select a date') . ($calendar_is_required ? ' <span class="text-red-500">*</span>' : '') . '</span>';
            if ($calendar_text !== '') {
                echo '<p class="text-sm text-gray-500 mb-2">' . esc_html($calendar_text) . '</p>';
            }

            $calendar_required_attr = $calendar_is_required ? ' required' : '';
            $has_preset_options = !empty($calendar_option_rows);

            if ($has_preset_options) {
                if ($calendar_sync_mode === 'due_date') {
                    echo '<select name="date" class="mt-1 block w-full" data-afb-due-date-source="1"' . $calendar_required_attr . '>';
                } elseif ($calendar_sync_mode === 'text' && $calendar_sync_gid !== '') {
                    echo '<select class="mt-1 block w-full" data-afb-sync-target="' . esc_attr($calendar_sync_gid) . '"' . $calendar_required_attr . '>';
                } else {
                    echo '<select name="description_inputs[' . esc_attr($id) . ']" class="mt-1 block w-full" data-afb-description-input="1" data-afb-description-id="' . esc_attr($id) . '" data-afb-description-label="' . esc_attr($calendar_label) . '"' . $calendar_required_attr . '>';
                }

                echo '<option value="">' . esc_html($calendar_placeholder !== '' ? $calendar_placeholder : '-- Select a date --') . '</option>';
                foreach ($calendar_option_rows as $calendar_option) {
                    $option_text = trim((string) $calendar_option);
                    if ($option_text === '') {
                        continue;
                    }
                    echo '<option value="' . esc_attr($option_text) . '">' . esc_html($option_text) . '</option>';
                }
                echo '</select>';
            } else {
                if ($calendar_sync_mode === 'due_date') {
                    echo '<input type="date" name="date" class="mt-1 block w-full" data-afb-due-date-source="1"' . $calendar_required_attr . '>';
                } elseif ($calendar_sync_mode === 'text' && $calendar_sync_gid !== '') {
                    echo '<input type="date" class="mt-1 block w-full" data-afb-sync-target="' . esc_attr($calendar_sync_gid) . '"' . $calendar_required_attr . '>';
                } else {
                    echo '<input type="date" name="description_inputs[' . esc_attr($id) . ']" class="mt-1 block w-full" data-afb-description-input="1" data-afb-description-id="' . esc_attr($id) . '" data-afb-description-label="' . esc_attr($calendar_label) . '"' . $calendar_required_attr . '>';
                }
            }

            echo '</label>';
            echo '</div>';
            continue;
        }

        if (strpos($id, 'section_') === 0) {
            $section_text  = $custom_sections[$id] ?? '';
            $section_title = $section_titles[$id] ?? '';

            if ($section_title || $section_text) {
                echo '<div class="w-full">';
                echo '<div class="afb-step-intro" data-step-break-id="' . esc_attr($id) . '">';
                if ($section_title) {
                    echo '<h3 class="afb-step-title">' . esc_html($section_title) . '</h3>';
                }
                if ($section_text) {
                    echo '<p class="afb-step-desc">' . esc_html($section_text) . '</p>';
                }
                echo '</div>';
                echo '</div>';
            }
            continue;
        }

        // Pseudo field: Notes (HTML) – full width textarea writing to task description
        if ($id === '__NOTES_HTML__') {
            if (in_array($id, $used_fields, true)) {
                $labelTxt = $labels[$id] ?? 'Notes';
                $desc     = $descriptions[$id] ?? '';

                echo '<div class="w-full">';
                echo '<label class="block mb-2" data-field-id="' . esc_attr($id) . '">';
                echo '<span class="text-gray-700">' . esc_html($labelTxt) . '</span>';
                if ($desc) echo '<p class="text-sm text-gray-500 mb-2">' . esc_html($desc) . '</p>';
                echo '<textarea name="asana_html_notes" class="mt-1 block w-full afb-notes-textarea" rows="6"></textarea>';
                echo '</label>';
                echo '</div>';
            }
            continue;
        }

        // Skip if unknown or not enabled
        if (!isset($field_map[$id]) || !in_array($id, $used_fields, true)) continue;

        $f            = $field_map[$id];
        $is_required  = in_array($id, $required_fields, true);
        $is_hidden    = in_array($id, $hidden_fields, true);
        $is_readonly  = in_array($id, $readonly_fields, true);
        $is_paragraph = in_array($id, $paragraph_fields, true);

        // ✅ NEW: half width
        $is_half      = in_array($id, $half_width_fields, true);

        $labelTxt     = $labels[$id] ?? ($f['name'] ?? '');
        $desc         = $descriptions[$id] ?? '';
        $type         = $f['type'] ?? 'text';
        $visible_option_ids = [];
        if (!empty($visible_enum_options[$id]) && is_array($visible_enum_options[$id])) {
            $visible_option_ids = array_values(array_unique(array_map('strval', $visible_enum_options[$id])));
        }

        if ($is_hidden) {
            echo '<input type="hidden" name="custom_fields[' . esc_attr($id) . ']" value="">';
            continue;
        }

        $requiredAttr = $is_required ? 'required' : '';
        $readonlyAttr = $is_readonly ? 'readonly' : '';

        // ✅ Container controls width
        $containerClass = 'w-full ' . ($is_half ? 'md:w-1/2' : 'md:w-full');

        echo '<div class="' . esc_attr($containerClass) . '">';
        echo '<label class="block mb-2" data-field-id="' . esc_attr($id) . '">';
        echo '<span class="text-gray-700">' . esc_html($labelTxt);
        if ($is_required) echo ' <span class="text-red-500">*</span>';
        echo '</span>';
        if ($desc) echo '<p class="text-sm text-gray-500 mb-2">' . esc_html($desc) . '</p>';

        switch ($type) {
            case 'text':
                $text_sync_gid = trim((string) ($text_sync_fields[$id] ?? ''));
                $has_text_sync_target = $text_sync_gid !== '' && ctype_digit($text_sync_gid) && $text_sync_gid !== $id;

                if ($is_paragraph) {
                    if ($has_text_sync_target) {
                        echo '<textarea class="mt-1 block w-full afb-paragraph-input" rows="4" data-afb-sync-target="' . esc_attr($text_sync_gid) . '" ' . $readonlyAttr . ' ' . $requiredAttr . '></textarea>';
                    } else {
                        echo '<textarea name="custom_fields[' . esc_attr($id) . ']" class="mt-1 block w-full afb-paragraph-input" rows="4" ' . $readonlyAttr . ' ' . $requiredAttr . '></textarea>';
                    }
                } else {
                    // light heuristic: email input if label suggests so
                    $inputType = stripos((string)$labelTxt, 'email') !== false ? 'email' : 'text';
                    if ($has_text_sync_target) {
                        echo '<input type="' . esc_attr($inputType) . '" class="mt-1 block w-full" data-afb-sync-target="' . esc_attr($text_sync_gid) . '" ' . $readonlyAttr . ' ' . $requiredAttr . '>';
                    } else {
                        echo '<input type="' . esc_attr($inputType) . '" name="custom_fields[' . esc_attr($id) . ']" class="mt-1 block w-full" ' . $readonlyAttr . ' ' . $requiredAttr . '>';
                    }
                }
                break;

            case 'enum':
                echo '<select name="custom_fields[' . esc_attr($id) . ']" class="mt-1 block w-full" ' . $readonlyAttr . ' ' . $requiredAttr . '>';
                echo '<option value="">-- Select --</option>';
                foreach ((array)($f['enum_options'] ?? []) as $option) {
                    if (!$option) continue;
                    if (isset($option['enabled']) && $option['enabled'] === false) continue;
                    $option_gid = (string)($option['gid'] ?? '');
                    if ($option_gid === '') continue;
                    if (!empty($visible_option_ids) && !in_array($option_gid, $visible_option_ids, true)) continue;
                    echo '<option value="' . esc_attr($option_gid) . '">' . esc_html($option['name']) . '</option>';
                }
                echo '</select>';
                break;

            case 'number':
                echo '<input type="number" step="any" name="custom_fields[' . esc_attr($id) . ']" class="mt-1 block w-full" ' . $readonlyAttr . ' ' . $requiredAttr . '>';
                break;

            case 'date':
                echo '<input type="date" name="custom_fields[' . esc_attr($id) . ']" class="mt-1 block w-full" ' . $readonlyAttr . ' ' . $requiredAttr . '>';
                break;

            default:
                echo '<input type="text" name="custom_fields[' . esc_attr($id) . ']" class="mt-1 block w-full" ' . $readonlyAttr . ' ' . $requiredAttr . '>';
        }

        echo '</label>';
        echo '</div>'; // width container
    }

    echo '</div>'; // afb-fields wrapper
}
