<?php

namespace GriffinForms\Admin\App\Html\Widgets\PresentationArea\FormElements;

use GriffinForms\Frontend\Views\GriffinFormsForm;
use GriffinForms\Items\FormTheme;

class Form extends \GriffinForms\Admin\App\Html\Widgets\PresentationArea\FormElements\Format
{
    /**
     * Bootstrap fallback classes applied when no theme is set.
     * These provide basic styling when a form has no custom theme assigned.
     */
    protected $bs_form_container_classes = '';
    protected $bs_form_heading_classes = 'h3 mb-0';
    protected $bs_form_description_classes = 'form-text text-muted mb-0';

    public function getHtml()
    {

        $theme_id = $this->item->getProp('form_theme');
        $this->form_theme = new \GriffinForms\Items\FormTheme();
        $this->form_theme->loadItem($theme_id);

        // Determine if theme is set for conditional class application
        $is_theme_set = $this->isThemeSet();
        $theme_class = !$is_theme_set ? ' gf-no-theme' : '';
        $additional_classes = !$is_theme_set && !empty($this->bs_form_container_classes) ? ' ' . esc_attr($this->bs_form_container_classes) : '';

        // Only get form styles if theme is set
        $css = $is_theme_set ? $this->form_theme->getFormStyleCss() : '';

        echo '<div id="' . esc_attr($this->getHtmlId($this->item_id)) . '" class="' . esc_attr('griffinforms-app-formlayout-form' . $theme_class . $additional_classes) . '" data-gf-form-selected="false" data-gf-itemid="' . absint($this->item_id) . '" data-gf-theme-id="' . absint($theme_id) . '" style="' . esc_attr($css) . '">';

        $this->renderPlaceholderStyles();
        $this->renderCheckboxRadioAccentStyles();
        $this->renderProgressBarStyles();

        echo '<div class="pt-5 gf-builder-form-meta-shell">';
        $this->formName();
        $this->formHeading();
        $this->formDescription();
        echo '</div>';

        $this->progressBar();
        $this->formPages();

        $this->addFormPage();
        $this->progressBarJs();

        echo '</div>';
    }

    private function formName()
    {
        echo '<div id="' . esc_attr($this->getHtmlId('name') . '-' . $this->item_id) . '" class="gf-hide-in-compact">';
        $this->textUpdateField(
            'name',
            array('placeholder' => __('Name cannot be empty', 'griffinforms-form-builder'), 'required' => 'required'),
            array('font-size' => '12px')
        );
        echo '</div>';
    }

    private function formHeading()
    {
        $is_theme_set = $this->isThemeSet();
        $css = $is_theme_set ? $this->form_theme->getFormTitleCss() : '';
        $heading_classes = '';

        if (!$is_theme_set && !empty($this->bs_form_heading_classes)) {
            $heading_classes = $this->bs_form_heading_classes;
        }

        $this->optionalMetadataField(
            'heading',
            array(
                'ghost_label'     => __('Add heading', 'griffinforms-form-builder'),
                'wrapper_id'      => $this->getHtmlId('heading'),
                'wrapper_classes' => 'gf-hide-in-compact',
                'field_classes'   => $heading_classes,
                'attrs'           => array(
                    'placeholder' => __('Optional heading', 'griffinforms-form-builder'),
                    'data-gf-metadata-editor' => 'true',
                ),
                'style'           => array($css),
            )
        );
    }

    private function formDescription()
    {
        $is_theme_set = $this->isThemeSet();
        $css = $is_theme_set ? $this->form_theme->getFormDescriptionCss() : '';
        $description_classes = '';

        if (!$is_theme_set && !empty($this->bs_form_description_classes)) {
            $description_classes = $this->bs_form_description_classes;
        }

        $this->optionalMetadataField(
            'description',
            array(
                'mode'            => 'textarea',
                'ghost_label'     => __('Add description', 'griffinforms-form-builder'),
                'wrapper_id'      => $this->getHtmlId('description'),
                'wrapper_classes' => 'gf-hide-in-compact',
                'field_classes'   => $description_classes,
                'attrs'           => array(
                    'placeholder' => __('Optional description', 'griffinforms-form-builder'),
                    'rows' => '2',
                    'data-gf-metadata-editor' => 'true',
                ),
                'style'           => array($css),
            )
        );
    }

    private function formPages()
    {
        $page_ids = $this->item->getProp('formpages');

        if (empty($page_ids) or !is_array($page_ids)) {
            return;
        }

        $total_pages = count($page_ids);

        foreach (array_values($page_ids) as $index => $page_id) {
            $page = new FormPage($page_id, $this->item_id, $this, $this->form_theme);

            $position_context = [
                'is_first' => $index === 0,
                'is_last'  => $index === ($total_pages - 1),
                'index'    => $index,
                'total'    => $total_pages
            ];

            $page->setPositionContext($position_context);
            $page->getHtml();
        }
    }

    private function progressBar()
    {
        $progress_bar = $this->item->getProp('progress_bar');
        if (!is_array($progress_bar) || empty($progress_bar['toggle'])) {
            return;
        }

        $page_ids = $this->item->getProp('formpages');
        if (!is_array($page_ids) || count($page_ids) <= 1) {
            return;
        }

        $style = isset($progress_bar['style']) && in_array($progress_bar['style'], array('stepper', 'tabs'), true) ? $progress_bar['style'] : 'stepper';
        $show_page_headings = !isset($progress_bar['show_page_headings']) || (bool) $progress_bar['show_page_headings'];
        $is_theme_set = $this->isThemeSet();
        $page_text = $is_theme_set ? $this->form_theme->getPageTextColor() : '#1d2327';
        $page_bg = $is_theme_set ? $this->form_theme->getPageBackgroundColor() : '#ffffff';
        $label_color = $is_theme_set ? $this->form_theme->getLabelColor() : $page_text;
        $description_color = $is_theme_set ? $this->form_theme->getFieldDescriptionColor() : '#6c757d';
        $accent_color = $is_theme_set ? $this->form_theme->getSubmitButtonBackgroundColor() : '#0d6efd';
        $progress_style = '--gf-progress-bar-accent: ' . esc_attr($accent_color) . '; --gf-progress-bar-muted: ' . esc_attr($description_color) . '; --gf-progress-bar-text: ' . esc_attr($page_text) . '; --gf-progress-bar-label: ' . esc_attr($label_color) . '; --gf-progress-bar-page-bg: ' . esc_attr($page_bg) . ';';
        $labels = array();
        $icons = array();

        foreach (array_values($page_ids) as $index => $page_id) {
            $page = new FormPage($page_id, $this->item_id, $this, $this->form_theme);
            $labels[] = $this->getProgressStepLabel($page, $index + 1, $show_page_headings);
            $icons[] = $this->getProgressStepIcon($page);
        }

        $active_step = 1;

        echo '<div class="griffinforms-progress-bar" data-gf-progress-bar="true" data-gf-progress-style="' . esc_attr($style) . '" data-gf-progress-active="' . absint($active_step) . '" data-gf-progress-total="' . absint(count($page_ids)) . '" style="' . esc_attr($progress_style) . '; margin: 1rem 0 1.5rem; color: ' . esc_attr($description_color) . ';">';
        echo '<div class="griffinforms-progress-bar__track" style="display:flex; gap:0.75rem; align-items:flex-start; flex-wrap:wrap; position:relative; padding-top:0.25rem;">';
        if ($style === 'stepper') {
            echo '<svg class="griffinforms-progress-bar__connector" aria-hidden="true" focusable="false" style="position:absolute; left:0; top:0; width:100%; overflow:visible; pointer-events:none; z-index:0;"></svg>';
        }
        foreach ($labels as $index => $label) {
            $step = $index + 1;
            $state = $step < $active_step ? 'complete' : ($step === $active_step ? 'active' : 'upcoming');
            $icon = $icons[$index] ?? '';
            echo '<div class="griffinforms-progress-bar__step" data-gf-progress-step="' . absint($step) . '" data-gf-progress-state="' . esc_attr($state) . '" data-gf-page-id="' . absint($page_ids[$index] ?? 0) . '">';
            $marker_class = 'griffinforms-progress-bar__marker' . ($icon !== '' ? ' griffinforms-progress-bar__marker--icon' : '');
            echo '<span class="' . esc_attr($marker_class) . '" aria-hidden="true">';
            echo $this->getProgressMarkerInnerHtml($step, $icon, $style);
            echo '<span class="griffinforms-progress-bar__marker-check" aria-hidden="true"></span>';
            echo '</span>';
            $label_input_style = 'width:100%; max-width:100%; background:transparent; border:0; box-shadow:none; padding:0; margin:0; text-align:center; font:inherit; line-height:inherit; color:inherit; pointer-events:auto; cursor:text;';
            echo '<input type="text" class="griffinforms-progress-bar__label griffinforms-app-text_update_field" data-gf-progress-label="true" data-gf-itemtype="formpage" data-gf-itemid="' . absint($page_ids[$index] ?? 0) . '" data-gf-fieldname="step_name" data-gf-fieldvalue="' . esc_attr($label) . '" value="' . esc_attr($label) . '" aria-label="' . esc_attr(sprintf(__('Edit step label for step %d', 'griffinforms-form-builder'), $step)) . '" style="' . esc_attr($label_input_style) . '">';
            echo '</div>';
        }
        echo '</div>';
        echo '</div>';
    }

    private function progressBarJs()
    {
        echo '<script>';
        echo '(function ($) {';
        echo 'function updateProgressBar(form) {';
        echo 'var progressBar = form.find(".griffinforms-progress-bar[data-gf-progress-bar=\'true\']").first();';
        echo 'if (!progressBar.length) { return; }';
        echo 'var currentStep = 1;';
        echo 'progressBar.attr("data-gf-progress-active", "1");';
        echo 'progressBar.find("[data-gf-progress-step]").each(function () {';
        echo 'var step = parseInt($(this).attr("data-gf-progress-step"), 10);';
        echo 'if (isNaN(step)) { return; }';
        echo 'var state = "upcoming";';
        echo 'if (step < currentStep) { state = "complete"; } else if (step === currentStep) { state = "active"; }';
        echo '$(this).attr("data-gf-progress-state", state);';
        echo '});';
        echo 'syncProgressBarLabels(form, progressBar);';
        echo 'syncProgressBarIcons(form, progressBar);';
        echo 'updateProgressBarGeometry(progressBar);';
        echo '}';
        echo 'function syncProgressBarLabels(form, progressBar) {';
        echo 'var pages = form.find(".griffinforms-app-formlayout-formpage-container");';
        echo 'progressBar.find("[data-gf-progress-step]").each(function (index) {';
        echo 'var stepEl = $(this);';
        echo 'var labelEl = stepEl.find(".griffinforms-progress-bar__label").first();';
        echo 'if (!labelEl.length) { return; }';
        echo 'var page = pages.eq(index);';
        echo 'if (!page.length) { return; }';
        echo 'var stepName = $.trim(page.attr("data-gf-step-name") || "");';
        echo 'if (stepName !== "") { labelEl.val(stepName).attr("data-gf-fieldvalue", stepName); return; }';
        echo 'var headingInput = page.find("[data-gf-fieldname=\'heading\']").first();';
        echo 'var heading = headingInput.length ? $.trim(headingInput.val() || headingInput.text() || "") : "";';
        echo 'if (heading !== "") {';
        echo 'labelEl.val(heading).attr("data-gf-fieldvalue", heading);';
        echo 'return;';
        echo '}';
        echo 'var nameInput = page.find("[data-gf-fieldname=\'name\']").first();';
        echo 'var name = nameInput.length ? $.trim(nameInput.val() || nameInput.text() || "") : "";';
        echo 'if (name !== "") {';
        echo 'labelEl.val(name).attr("data-gf-fieldvalue", name);';
        echo 'return;';
        echo '}';
        echo 'var fallback = "Step " + (index + 1);';
        echo 'labelEl.val(fallback).attr("data-gf-fieldvalue", fallback);';
        echo '});';
        echo '}';
        echo 'function saveProgressBarLabel(form, field) {';
        echo 'var labelEl = field.closest(".griffinforms-progress-bar__step").find(".griffinforms-progress-bar__label").first();';
        echo 'var pageStep = labelEl.closest("[data-gf-progress-step]").first();';
        echo 'var pageId = parseInt(field.attr("data-gf-itemid") || pageStep.attr("data-gf-page-id") || "0", 10);';
        echo 'if (!pageId) { return; }';
        echo 'var value = $.trim(field.val() || "");';
        echo 'var currentValue = $.trim(labelEl.attr("data-gf-fieldvalue") || "");';
        echo 'if (value === currentValue) {';
        echo 'return;';
        echo '}';
        echo 'statusbarMsg("waiting");';
        echo 'var data = {';
        echo '"action": "updatePageStepData",';
        echo '"page_id": pageId,';
        echo '"step_name": value,';
        echo '"form_id": form.attr("data-gf-itemid"),';
        echo '"nonce": "' . esc_js(wp_create_nonce('update_page_step_data')) . '"';
        echo '};';
        echo '$.post(ajaxurl, data, function (response) {';
        echo 'response = JSON.parse(response);';
        echo 'if (response.success) {';
        echo 'var updatedValue = response.updated_value && response.updated_value.step_name ? response.updated_value.step_name : "";';
        echo 'var fallback = currentValue || "";';
        echo 'var page = form.find(".griffinforms-app-formlayout-formpage-container[data-gf-itemid=\'" + pageId + "\']").first();';
        echo 'labelEl.val(updatedValue !== "" ? updatedValue : fallback);';
        echo 'field.val(updatedValue !== "" ? updatedValue : fallback);';
        echo 'field.attr("data-gf-fieldvalue", updatedValue);';
        echo 'if (page.length) { page.attr("data-gf-step-name", updatedValue); }';
        echo 'statusbarMsg("success", response.message + " @ " + response.time);';
        echo 'if (typeof griffinformsFetchBuilderWarningCount === "function") { griffinformsFetchBuilderWarningCount(); }';
        echo 'document.dispatchEvent(new CustomEvent("form-updated", { detail: { type: "step_data", formId: data.form_id, itemId: pageId } }));';
        echo '} else {';
        echo 'statusbarMsg("warning", response.message);';
        echo 'field.val(currentValue);';
        echo '}';
        echo '});';
        echo '}';
        echo 'function syncProgressBarIcons(form, progressBar) {';
        echo 'progressBar.find("[data-gf-progress-step]").each(function (index) {';
        echo 'var stepEl = $(this);';
        echo 'var pageId = parseInt(stepEl.attr("data-gf-page-id") || "0", 10);';
        echo 'var page = pageId ? form.find(".griffinforms-app-formlayout-formpage-container[data-gf-itemid=\'" + pageId + "\']").first() : $();';
        echo 'if (!page.length) {';
        echo 'page = form.find(".griffinforms-app-formlayout-formpage-container").eq(index);';
        echo '}';
        echo 'if (!page.length) { return; }';
        echo 'var icon = $.trim(page.attr("data-gf-step-icon") || page.find("[data-gf-step-icon]").first().attr("data-gf-step-icon") || "");';
        echo 'var progressStyle = progressBar.attr("data-gf-progress-style") || "stepper";';
        echo 'var iconColor = "#ffffff";';
        echo 'if (icon !== "") {';
        echo 'var marker = stepEl.find(".griffinforms-progress-bar__marker").first();';
        echo 'if (marker.length === 0) {';
        echo 'marker = $(\'<span class="griffinforms-progress-bar__marker" aria-hidden="true"><span class="griffinforms-progress-bar__marker-check" aria-hidden="true"></span></span>\');';
        echo 'stepEl.prepend(marker);';
        echo '}';
        echo 'marker.find(".griffinforms-progress-bar__marker-number").remove();';
        echo 'if (marker.find(".griffinforms-progress-bar__marker-icon").length === 0) {';
        echo 'marker.prepend(\'<span class="material-symbols-outlined griffinforms-progress-bar__marker-icon" aria-hidden="true" style="font-family:\\\'Material Symbols Outlined\\\' !important; font-weight:400 !important; font-style:normal !important; font-size:1.25rem; line-height:1; letter-spacing:normal; text-transform:none; display:inline-block; white-space:nowrap; word-wrap:normal; direction:ltr; text-rendering:optimizeLegibility; -webkit-font-smoothing:antialiased; font-variation-settings:\\\'FILL\\\' 0, \\\'wght\\\' 400, \\\'GRAD\\\' 0, \\\'opsz\\\' 24; color:\' + iconColor + \' !important; -webkit-text-fill-color:\' + iconColor + \' !important; transform:translateY(0);">\' + icon + \'</span>\');';
        echo '}';
        echo '} else {';
        echo 'var marker = stepEl.find(".griffinforms-progress-bar__marker").first();';
        echo 'if (marker.length === 0) {';
        echo 'marker = $(\'<span class="griffinforms-progress-bar__marker" aria-hidden="true"><span class="griffinforms-progress-bar__marker-number" style="color:#fff;">\' + (index + 1) + \'</span><span class="griffinforms-progress-bar__marker-check" aria-hidden="true"></span></span>\');';
        echo 'stepEl.prepend(marker);';
        echo '}';
        echo 'marker.find(".griffinforms-progress-bar__marker-icon").remove();';
        echo 'if (marker.find(".griffinforms-progress-bar__marker-number").length === 0) {';
        echo 'marker.prepend(\'<span class="griffinforms-progress-bar__marker-number" style="color:#fff;">\' + (index + 1) + \'</span>\');';
        echo '}';
        echo '}';
        echo '});';
        echo '}';
        echo 'function updateProgressBarGeometry(progressBar) {';
        echo 'var track = progressBar.find(".griffinforms-progress-bar__track").first();';
        echo 'var connector = progressBar.find(".griffinforms-progress-bar__connector").first();';
        echo 'var markers = progressBar.find(".griffinforms-progress-bar__marker");';
        echo 'if (!track.length || !connector.length || markers.length < 2) { connector.empty(); return; }';
        echo 'var trackRect = track[0].getBoundingClientRect();';
        echo 'var markerRects = markers.map(function () { return this.getBoundingClientRect(); }).get();';
        echo 'var lineY = (markerRects[0].top + (markerRects[0].height / 2)) - trackRect.top;';
        echo 'connector.attr("width", Math.max(trackRect.width, 1));';
        echo 'connector.attr("height", Math.max(lineY * 2, markerRects[0].height, 1));';
        echo 'connector.removeAttr("viewBox").removeAttr("preserveAspectRatio");';
        echo 'var svgRect = connector[0].getBoundingClientRect();';
        echo 'var stateMap = progressBar.find(".griffinforms-progress-bar__step").map(function () { return $(this).attr("data-gf-progress-state") || "upcoming"; }).get();';
        echo 'var segments = [];';
        echo 'for (var i = 0; i < markerRects.length - 1; i++) {';
        echo 'var leftRect = markerRects[i];';
        echo 'var rightRect = markerRects[i + 1];';
        echo 'var x1 = leftRect.right - svgRect.left;';
        echo 'var x2 = rightRect.left - svgRect.left;';
        echo 'var state = stateMap[i + 1] || "upcoming";';
        echo 'var stroke = state === "upcoming" ? "var(--gf-progress-bar-muted, var(--bs-secondary, #6c757d))" : "var(--gf-progress-bar-accent, var(--bs-primary, #0d6efd))";';
        echo 'segments.push(\'<line class="griffinforms-progress-bar__connector-line" style="stroke:\' + stroke + \';" x1="\' + x1 + \'" y1="\' + lineY + \'" x2="\' + x2 + \'" y2="\' + lineY + \'"></line>\');';
        echo '}';
        echo 'connector.html(segments.join(""));';
        echo '}';
        echo 'function rebuildProgressBarSteps(form, progressBar) {';
        echo 'var pages = form.find(".griffinforms-app-formlayout-formpage-container");';
        echo 'var track = progressBar.find(".griffinforms-progress-bar__track").first();';
        echo 'var pageCount = pages.length;';
        echo 'var stepEls = progressBar.find("[data-gf-progress-step]");';
        echo 'var stepCount = stepEls.length;';
        // Add missing steps
        echo 'for (var i = stepCount; i < pageCount; i++) {';
        echo 'var pageId = parseInt(pages.eq(i).attr("data-gf-itemid") || "0", 10);';
        echo 'var stepEl = $("<div class=\"griffinforms-progress-bar__step\" data-gf-progress-step=\"" + (i + 1) + "\" data-gf-progress-state=\"upcoming\" data-gf-page-id=\"" + pageId + "\"></div>");';
        echo 'var marker = $("<span class=\"griffinforms-progress-bar__marker\" aria-hidden=\"true\"><span class=\"griffinforms-progress-bar__marker-number\" style=\"color:#fff;\">" + (i + 1) + "</span><span class=\"griffinforms-progress-bar__marker-check\" aria-hidden=\"true\"></span></span>");';
        echo 'var labelStyle = "width:100%;max-width:100%;background:transparent;border:0;box-shadow:none;padding:0;margin:0;text-align:center;font:inherit;line-height:inherit;color:inherit;pointer-events:auto;cursor:text;";';
        echo 'var labelEl = $("<input type=\"text\" class=\"griffinforms-progress-bar__label griffinforms-app-text_update_field\" data-gf-progress-label=\"true\" data-gf-itemtype=\"formpage\" data-gf-fieldname=\"step_name\" data-gf-fieldvalue=\"\" value=\"\" />").attr("data-gf-itemid", pageId).attr("style", labelStyle);';
        echo 'stepEl.append(marker).append(labelEl);';
        echo 'track.append(stepEl);';
        echo '}';
        // Remove extra steps
        echo 'progressBar.find("[data-gf-progress-step]").each(function (index) {';
        echo 'if (index >= pageCount) { $(this).remove(); }';
        echo '});';
        // Renumber all steps and sync page IDs
        echo 'progressBar.find("[data-gf-progress-step]").each(function (index) {';
        echo 'var page = pages.eq(index);';
        echo 'var pageId = parseInt((page.length ? page.attr("data-gf-itemid") : "0") || "0", 10);';
        echo '$(this).attr("data-gf-progress-step", index + 1).attr("data-gf-page-id", pageId);';
        echo '$(this).find(".griffinforms-progress-bar__label").attr("data-gf-itemid", pageId);';
        echo '$(this).find(".griffinforms-progress-bar__marker-number").text(index + 1);';
        echo '});';
        echo 'progressBar.attr("data-gf-progress-total", String(pageCount));';
        echo '}';
        echo '$(function () {';
        echo 'var form = $(".griffinforms-app-formlayout-form[data-gf-itemid=' . absint($this->item_id) . ']");';
        echo 'if (!form.length) { return; }';
        echo 'updateProgressBar(form);';
        echo 'updateProgressBarGeometry(form);';
        echo 'document.addEventListener("form-updated", function (event) {';
        echo 'var detail = event && event.detail ? event.detail : {};';
        echo 'if (!detail || String(detail.formId || "") !== form.attr("data-gf-itemid")) { return; }';
        echo 'var type = String(detail.type || "");';
        echo 'if (["heading", "theme", "page_order", "page_deleted", "page_added", "step_data"].indexOf(type) === -1) { return; }';
        echo 'var progressBar = form.find(".griffinforms-progress-bar[data-gf-progress-bar=\'true\']").first();';
        echo 'if (type === "page_added" || type === "page_deleted") {';
        echo 'requestAnimationFrame(function () {';
        echo 'rebuildProgressBarSteps(form, progressBar);';
        echo 'updateProgressBar(form);';
        echo 'updateProgressBarGeometry(form);';
        // Observe any newly added page containers for selection changes
        echo '});';
        echo '} else {';
        echo 'requestAnimationFrame(function () { updateProgressBar(form); updateProgressBarGeometry(form); });';
        echo '}';
        echo '});';
        echo 'form.on("input change", "[data-gf-fieldname=\'heading\'], [data-gf-fieldname=\'name\'], #griffinforms-stepdata-stepname-inputtext", function () { requestAnimationFrame(function () { updateProgressBar(form); }); });';
        echo '$(window).on("resize", function () { requestAnimationFrame(function () { updateProgressBarGeometry(form); }); });';
        echo '});';
        echo '})(jQuery);';
        echo '</script>';
    }

    private function getProgressStepLabel(\GriffinForms\Admin\App\Html\Widgets\PresentationArea\FormElements\FormPage $page, int $step, bool $show_page_headings): string
    {
        $step_data = $page->getProp('step_data');
        if (is_array($step_data)) {
            $step_name = trim((string) ($step_data['step_name'] ?? ''));
            if ($step_name !== '') {
                return $step_name;
            }
        }

        $heading = trim((string) $page->getProp('heading'));
        if ($show_page_headings && $heading !== '') {
            return $heading;
        }

        $name = trim((string) $page->getProp('name'));
        if ($show_page_headings && $name !== '') {
            return $name;
        }

        return sprintf(__('Step %d', 'griffinforms-form-builder'), $step);
    }

    private function getProgressStepIcon(\GriffinForms\Admin\App\Html\Widgets\PresentationArea\FormElements\FormPage $page): string
    {
        $step_data = $page->getProp('step_data');
        if (!is_array($step_data)) {
            return '';
        }

        return trim((string) ($step_data['step_icon'] ?? ''));
    }

    private function getProgressMarkerInnerHtml(int $step, string $icon, string $style = 'stepper'): string
    {
        if ($icon !== '') {
            $icon_color = '#ffffff';
            return '<span class="material-symbols-outlined griffinforms-progress-bar__marker-icon" aria-hidden="true" style="font-family:\'Material Symbols Outlined\' !important; font-weight:400 !important; font-style:normal !important; font-size:1.25rem; line-height:1; letter-spacing:normal; text-transform:none; display:inline-block; white-space:nowrap; word-wrap:normal; direction:ltr; text-rendering:optimizeLegibility; -webkit-font-smoothing:antialiased; font-variation-settings:\'FILL\' 0, \'wght\' 400, \'GRAD\' 0, \'opsz\' 24; color:' . $icon_color . ' !important; -webkit-text-fill-color:' . $icon_color . ' !important;">' . esc_html($icon) . '</span>';
        }

        return '<span class="griffinforms-progress-bar__marker-number" style="color:#fff;">' . absint($step) . '</span>';
    }

    private function addFormPage()
    {
        echo '<div id="' . esc_attr($this->getHtmlId('add-formpage-section')) . '" class="text-center mt-5 visually-hidden">';
        echo '<div class="mb-3">';
        esc_html_e('Your form does not have a page yet!', 'griffinforms-form-builder');
        echo '</div>';
        $this->addFormPageBtn();
        echo '</div>';
    }

    private function addFormPageBtn()
    {
        $this->buttons->bsBtn([
            'class' => 'gf-btn-light btn-sm',
            'id'    => $this->getHtmlId('add-formpage-btn'),
            'label' => __('Add Page', 'griffinforms-form-builder'),
            'icon'  => 'add',
            'data'  => [
                'data-gf-action=insert_new_page',
                'data-gf-formid=' . $this->item_id,
                'data-gf-prevpage=null'
            ]
        ]);
    }

    /**
     * Renders placeholder color styling using the theme's label color.
     * Applies to all input and textarea elements in the form.
     * Only renders when a custom theme is assigned.
     */
    private function renderPlaceholderStyles()
    {
        // Skip rendering if no theme is set (use Bootstrap fallback only)
        if (!$this->isThemeSet()) {
            return;
        }

        $label_color = $this->form_theme->getFieldDescriptionColor();

        if (empty($label_color)) {
            return;
        }

        $css_rules = '.griffinforms-app-formlayout-form input::placeholder, ';
        $css_rules .= '.griffinforms-app-formlayout-form textarea::placeholder, ';
        $css_rules .= '.griffinforms-app-formlayout-form [useragentpart="placeholder"] { ';
        $css_rules .= 'color: ' . esc_attr($label_color) . ' !important; ';
        $css_rules .= 'opacity: 1 !important; ';
        $css_rules .= 'font-size: 0.92em; ';
        $css_rules .= 'font-weight: 400; ';
        $css_rules .= 'letter-spacing: 0.01em; ';
        $css_rules .= 'line-height: 1.35; }';

        $css_rules = FormTheme::prepareStyleTagContent($css_rules);
        if ($css_rules !== '') {
            echo '<style>' . $css_rules . '</style>';
        }
    }

    /**
     * Renders accent color styling for checkbox and radio inputs.
     * Uses utility class to apply the theme's checkbox_radio accent color to all checkbox/radio elements.
     * Overrides WordPress default checkbox/radio SVG styling and applies native browser styling.
     * Only renders when a custom theme is assigned.
     */
    private function renderCheckboxRadioAccentStyles()
    {
        // Skip rendering if no theme is set (use Bootstrap fallback only)
        if (!$this->isThemeSet()) {
            return;
        }

        $accent_color = $this->form_theme->getCheckboxRadioAccentColor();

        if (empty($accent_color)) {
            return;
        }

        $css_rules = '.gf-checkbox-radio-input { ';
        // Negate WordPress default checkbox/radio styling
        $css_rules .= 'border: none !important; ';
        $css_rules .= 'border-radius: 0 !important; ';
        $css_rules .= 'background: transparent !important; ';
        $css_rules .= 'color: inherit !important; ';
        $css_rules .= 'box-shadow: none !important; ';
        $css_rules .= 'transition: none !important; ';
        $css_rules .= '-webkit-appearance: auto !important; ';
        // Apply accent color from theme
        $css_rules .= 'accent-color: ' . esc_attr($accent_color) . ' !important; ';
        $css_rules .= '}';

        // Override WordPress ::before pseudo-element SVG checkmark/dot for checked state
        $css_rules .= '.gf-checkbox-radio-input:checked::before { ';
        $css_rules .= 'content: none !important; ';
        $css_rules .= '}';

        $css_rules = FormTheme::prepareStyleTagContent($css_rules);
        if ($css_rules !== '') {
            echo '<style>' . $css_rules . '</style>';
        }
    }

    /**
     * Renders progress bar styling so the builder preview matches frontend parity.
     */
    private function renderProgressBarStyles()
    {
        $progress_bar = $this->item->getProp('progress_bar');
        if (!is_array($progress_bar) || empty($progress_bar['toggle'])) {
            return;
        }

        $page_ids = $this->item->getProp('formpages');
        if (!is_array($page_ids) || count($page_ids) <= 1) {
            return;
        }

        $is_theme_set = $this->isThemeSet();
        $page_text = $is_theme_set ? $this->form_theme->getPageTextColor() : '#1d2327';
        $page_bg = $is_theme_set ? $this->form_theme->getPageBackgroundColor() : '#ffffff';
        $label_color = $is_theme_set ? $this->form_theme->getLabelColor() : $page_text;
        $description_color = $is_theme_set ? $this->form_theme->getFieldDescriptionColor() : '#6c757d';
        $accent_color = $is_theme_set ? $this->form_theme->getSubmitButtonBackgroundColor() : '#0d6efd';

        $scope = '.griffinforms-app-formlayout-form[data-gf-itemid="' . absint($this->item_id) . '"]';
        $css_rules = $scope . ' { ';
        $css_rules .= '--gf-progress-bar-accent: ' . esc_attr($accent_color) . '; ';
        $css_rules .= '--gf-progress-bar-muted: ' . esc_attr($description_color) . '; ';
        $css_rules .= '--gf-progress-bar-text: ' . esc_attr($page_text) . '; ';
        $css_rules .= '--gf-progress-bar-label: ' . esc_attr($label_color) . '; ';
        $css_rules .= '--gf-progress-bar-page-bg: ' . esc_attr($page_bg) . '; ';
        $css_rules .= '}';

        $css_rules .= $scope . ' .griffinforms-progress-bar { margin: 0 0 1rem; color: var(--gf-progress-bar-muted, #6c757d); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__track { display: flex; gap: 0.75rem; align-items: flex-start; flex-wrap: wrap; position: relative; padding-top: 0.25rem; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__connector { position: absolute; left: 0; top: 0; width: 100%; overflow: visible; pointer-events: none; z-index: 0; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__connector-line { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linecap: round; stroke: currentColor; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__step { color: var(--gf-progress-bar-muted, #6c757d); cursor: default; pointer-events: none; position: relative; z-index: 1; padding-top: 0; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="stepper"] .griffinforms-progress-bar__step { flex: 1 1 0; text-align: center; position: relative; display: flex; flex-direction: column; align-items: center; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="tabs"] .griffinforms-progress-bar__step { flex: 1 1 0; text-align: center; border: 1px solid rgba(0, 0, 0, 0.08); border-radius: 0.75rem; padding: 0.5rem 0.75rem; background: var(--gf-progress-bar-page-bg, #fff); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="tabs"] .griffinforms-progress-bar__connector { display: none; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="tabs"] .griffinforms-progress-bar__step[data-gf-progress-state="active"] { border-color: color-mix(in srgb, var(--gf-progress-bar-accent, #0d6efd) 35%, transparent); background: color-mix(in srgb, var(--gf-progress-bar-accent, #0d6efd) 8%, transparent); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="tabs"] .griffinforms-progress-bar__step[data-gf-progress-state="complete"] { background: var(--gf-progress-bar-page-bg, #fff); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="active"], ' . $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="complete"] { color: var(--gf-progress-bar-accent, #0d6efd); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__marker { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; border-radius: 999px; background: var(--gf-progress-bar-muted, #6c757d); margin-bottom: 0; line-height: 1; position: relative; z-index: 1; flex-shrink: 0; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="active"] .griffinforms-progress-bar__marker, ' . $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="complete"] .griffinforms-progress-bar__marker { background: var(--gf-progress-bar-accent, #0d6efd); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__marker--icon { width: auto; height: auto; min-width: 1.5rem; min-height: 1.5rem; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="stepper"] .griffinforms-progress-bar__marker--icon { width: 1.5rem; height: 1.5rem; background: var(--gf-progress-bar-muted, #6c757d); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="stepper"] .griffinforms-progress-bar__step[data-gf-progress-state="active"] .griffinforms-progress-bar__marker--icon, ' . $scope . ' .griffinforms-progress-bar[data-gf-progress-style="stepper"] .griffinforms-progress-bar__step[data-gf-progress-state="complete"] .griffinforms-progress-bar__marker--icon { background: var(--gf-progress-bar-accent, #0d6efd); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="stepper"] .griffinforms-progress-bar__marker--icon .griffinforms-progress-bar__marker-icon { color: #fff; display: block; line-height: 1; transform: translateY(0); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar[data-gf-progress-style="tabs"] .griffinforms-progress-bar__marker--icon .griffinforms-progress-bar__marker-icon { background: transparent; width: auto; height: auto; min-width: 0; min-height: 0; transform: translateY(0); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__marker-number { font-size: 0.75rem; font-weight: 700; color: #fff; line-height: 1; transform: none; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__marker-icon { font-size: 1.25rem; line-height: 1; color: #fff; display: inline-block; transform: translateY(0); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__label { display: block; font-size: 0.875rem; line-height: 1.2; color: var(--gf-progress-bar-muted, #6c757d); margin-top: 0.1rem; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="active"] .griffinforms-progress-bar__label, ' . $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="complete"] .griffinforms-progress-bar__label { color: var(--gf-progress-bar-accent, #0d6efd); }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__marker-check { display: none; position: relative; width: 0.75rem; height: 0.45rem; border-left: 0.15rem solid #fff; border-bottom: 0.15rem solid #fff; transform: rotate(-45deg) translateY(-1px); transform-origin: center; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="complete"] .griffinforms-progress-bar__marker-number { display: none; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="complete"] .griffinforms-progress-bar__marker-check { display: block; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__marker--icon + .griffinforms-progress-bar__marker-check { display: none; }';
        $css_rules .= $scope . ' .griffinforms-progress-bar__step[data-gf-progress-state="complete"] .griffinforms-progress-bar__marker--icon .griffinforms-progress-bar__marker-check { display: none; }';
        $css_rules .= '@media (prefers-reduced-motion: reduce) { ' . $scope . ' .griffinforms-progress-bar * { transition: none !important; animation: none !important; } }';

        $css_rules = FormTheme::prepareStyleTagContent($css_rules);
        if ($css_rules !== '') {
            echo '<style>' . $css_rules . '</style>';
        }
    }
}
