<?php

namespace GriffinForms\Admin\App\Html\Widgets\LeftSidebar;

final class FieldSelection extends \GriffinForms\Admin\App\Html\Widgets\LeftSidebar\Format
{
  
  public function getHtml()
  {
    echo '<div data-gf-leftsidebar-panel="fields" class="gf-leftsidebar-panel">';
    $this->categoryTabs();
    $this->categoryTabPanes();
    echo '</div>';
  }

  private function categoryTabs()
  {
    $tabs = array(
      array('id' => $this->getHtmlId('field-types-tab'), 'label' => __('Field Types', 'griffinforms-form-builder')),
      array('id' => $this->getHtmlId('reusable-fields-tab'), 'label' => __('Reusable Fields', 'griffinforms-form-builder'))
    );

    $bs_tabs = \GriffinForms\Admin\App\Html\Elements\BsTabs::getInstance();
    $bs_tabs->navTabs($tabs);
  }

  private function categoryTabPanes()
  {
    echo '<div class="tab-content p-3" id="' . esc_attr($this->getHtmlId('fieldselection-tab-content')) . '">';
    $this->fieldTypesPane();
    $this->reusableFieldsPane();
    echo '</div>';
  }

  private function fieldTypesPane()
  {
    echo '<div class="tab-pane fade show active small px-" id="' . esc_attr($this->getHtmlId('field-types-tab-pane')) . '" role="tabpanel" tabindex="0">';
    $this->commonFieldTypes();
    $this->advancedFieldTypes();
    $this->proFieldTypes();
    echo '</div>';
  }

  private function commonFieldTypes()
  {
    $field_definitions = $this->config->getFieldDefinitionsByCategory('common');

    echo '<div class="fw-bold my-2 text-uppercase" style="font-size: 10px;">';
    esc_html_e('Common Fields', 'griffinforms-form-builder');
    echo '</div>';
    echo '<div class="row g-2">';
    foreach ($field_definitions as $field_definition) {
      $field_type = (string) ($field_definition['field_type'] ?? '');
      if ($field_type === '') {
        continue;
      }

      $this->fieldTypePill($field_type, $this->config->getFriendlyName($field_type));
    }
    echo '</div>';
  }

  private function advancedFieldTypes()
  {
    $field_definitions = $this->config->getFieldDefinitionsByCategory('advanced');

    $pro_field_types = [];
    if (\GriffinForms\Admin\Menu::isProEnabled()) {
      $extension_registry = \GriffinForms\Includes\Extensions\ExtensionRegistry::getInstance();
      $pro_field_types = $extension_registry->getFieldTypesByExtension('pro');
    }

    echo '<div class="fw-bold mt-4 mb-2 text-uppercase" style="font-size: 10px;">';
    esc_html_e('Advanced Fields', 'griffinforms-form-builder');
    echo '</div>';
    echo '<div class="row g-2">';
    foreach ($field_definitions as $field_definition) {
      $field_type = (string) ($field_definition['field_type'] ?? '');
      if ($field_type === '' || in_array($field_type, $pro_field_types, true)) {
        continue;
      }

      $this->fieldTypePill($field_type, $this->config->getFriendlyName($field_type));
    }
    echo '</div>';
  }

  private function proFieldTypes()
  {
    if (!\GriffinForms\Admin\Menu::isProEnabled()) {
      return;
    }

    $extension_registry = \GriffinForms\Includes\Extensions\ExtensionRegistry::getInstance();
    $pro_field_types = $extension_registry->getFieldTypesByExtension('pro');

    $admission = \GriffinForms\Includes\Packages\PackageAdmission::getInstance();
    $pro_admitted = $admission->canAdmitPackage('pro', true);

    echo '<div class="fw-bold mt-4 mb-2 text-uppercase" style="font-size: 10px;">';
    esc_html_e('Pro Fields', 'griffinforms-form-builder');
    echo '</div>';
    echo '<div class="row g-2">';
    foreach ($pro_field_types as $field_type) {
      $this->proFieldPill($field_type, $this->config->getFriendlyName($field_type), $pro_admitted);
    }
    echo '</div>';
  }

  private function proFieldPill($type, $label, $pro_admitted)
  {
    $badge = new \GriffinForms\Admin\Html\Elements\ProBadge('Pro', 'gradient');

    echo '<div class="col-md-12">';

    $extra = $pro_admitted ? ' data-gf-fieldtype="' . esc_attr($type) . '"' : '';
    $draggable_class = $pro_admitted ? ' gf-app-new-field-pill gf-app-field-pill' : '';
    echo '<div class="' . esc_attr(trim('gf-app-pro-field-pill' . $draggable_class)) . ' text-start py-3 px-3 rounded-1 d-flex justify-content-start align-items-center" ';
    echo 'id="' . esc_attr($this->getHtmlId($type . '-field-pill')) . '"' . $extra . '>';

    $this->fieldTypeIcon($type);
    echo '<div class="small ms-2" style="font-weight:500; letter-spacing: 0.5px;">' . esc_html($label) . '</div>';
    if (!$pro_admitted) {
      echo '<div class="ms-auto ps-2">';
      ob_start();
      $badge->html();
      echo ob_get_clean();
      echo '</div>';
    }

    if ($pro_admitted) {
      echo '<div class="ms-2 spinner-border spinner-border-sm visually-hidden" role="status">';
      echo '<span class="visually-hidden">Loading...</span>';
      echo '</div>';
    }

    echo '</div>';

    echo '</div>';
  }

  private function fieldTypePill($type, $label)
  {
    echo '<div class="col-md-12">';
    echo '<div class="gf-app-new-field-pill gf-app-field-pill text-start bg-light py-3 px-3 rounded-1 d-flex justify-content-start align-items-center" ';
    echo 'id="' . esc_attr($this->getHtmlId($type . '-field-pill')) . '" ';
    echo 'data-gf-fieldtype="' . esc_attr($type) . '">';
    $this->fieldTypeIcon($type);
    echo '<div class="small ms-2" style="font-weight:500; letter-spacing: 0.5px;">' . esc_html($label) . '</div>';
    echo '<div class="ms-2 spinner-border spinner-border-sm visually-hidden" role="status">';
    echo '<span class="visually-hidden">Loading...</span>';
    echo '</div>';
    echo '</div>';
    echo '</div>';
  }

  private function reusableFieldsPane()
  {
    echo '<div class="tab-pane fade overflow-y-auto" id="' . esc_attr($this->getHtmlId('reusable-fields-tab-pane')) . '" role="tabpanel" tabindex="0" style="height:auto">';
    echo '<div class="row g-3"></div>';
    echo '</div>';
  }

  public function getJs()
  {
    $this->setReusableFieldsHeightJs();
    $this->tabsUnderlineJs();
    $this->toggleFieldSelectionJs();
    $this->makeFieldPillsDraggableJs();
    $this->getReusableFieldsJs();
  }

  private function setReusableFieldsHeightJs()
  {
    echo '
    const tabEl = document.querySelector("#griffinforms-app-fieldselection-reusable-fields-tab");
    tabEl.addEventListener("shown.bs.tab", event => {
      setReusableFieldsHeight();
    })
    
    function setReusableFieldsHeight() {
      let totalHeight = $("#griffinforms-app-rightsidebar").height();
      $("#griffinforms-app-fieldselection-reusable-fields-tab-pane").height(totalHeight);
    }
    ';
  }

  private function tabsUnderlineJs()
  {
    echo '
    const fieldTypesTab = $("#' . esc_js($this->getHtmlId('field-types-tab')) . '");
    const reusableTab = $("#' . esc_js($this->getHtmlId('reusable-fields-tab')) . '");
    const tabsNav = fieldTypesTab.closest(".nav-underline");

    function updateLeftSidebarUnderline(tabEl) {
      if (!tabEl || !tabEl.length || !tabsNav.length) {
        return;
      }
      const navOffset = tabsNav.offset();
      const tabOffset = tabEl.offset();
      if (!navOffset || !tabOffset) {
        return;
      }
      const left = tabOffset.left - navOffset.left;
      const width = tabEl.outerWidth();
      tabsNav.css("--gf-lefttab-underline-left", left + "px");
      tabsNav.css("--gf-lefttab-underline-width", width + "px");
    }

    if (tabsNav.length) {
      const activeTab = tabsNav.find(".nav-link.active").first();
      updateLeftSidebarUnderline(activeTab);

      tabsNav.on("mouseenter", ".nav-link", function() {
        updateLeftSidebarUnderline($(this));
      });

      tabsNav.on("mouseleave", function() {
        const currentActive = tabsNav.find(".nav-link.active").first();
        updateLeftSidebarUnderline(currentActive);
      });

      fieldTypesTab.on("shown.bs.tab", function() {
        updateLeftSidebarUnderline($(this));
      });

      reusableTab.on("shown.bs.tab", function() {
        updateLeftSidebarUnderline($(this));
      });
    }
    ';
  }

  private function toggleFieldSelectionJs()
  {
    echo '
    document.addEventListener("item-selected", () => {

      let itemType = $("[data-gf-selected=true]").attr("data-gf-itemtype")
      
      if (itemType === "rowcolumn" || itemType === "pagerow") {
        return;
      }

      $("#griffinforms-app-rightsidebar-field-selection").hide();
      });
    
    document.addEventListener("item-deselected", () => {
      $("#griffinforms-app-rightsidebar-field-selection").show();
    });
    ';
  }

  private function makeFieldPillsDraggableJs()
  {
    echo '
    makeFieldPillsDraggable();

    function makeFieldPillsDraggable() {
      $(".gf-app-new-field-pill").draggable({
        appendTo: "body",
        cursor: "grab",
        helper: function() {
          const clone = $(this).clone();
          clone.width($(this).outerWidth());
          return clone;
        },
        connectToSortable: "[data-gf-itemtype=rowcolumn]",
        zIndex: 999999999,
        start: function(event, ui) {
          const hasColumn = $(".griffinforms-app-formlayout-rowcolumn").length > 0;
          if (!hasColumn) {
            if (typeof statusbarMsg === "function") {
              statusbarMsg("warning", "' . esc_js(__('Add column before dropping a field.', 'griffinforms-form-builder')) . '");
            }
            return false;
          }
          $(ui.helper).addClass("shadow bg-white");
          $(".griffinforms-app-formlayout-rowcolumn").addClass("griffinforms-fe-droppable");
          ui.helper.css({
            width: $(this).outerWidth(),
            position: "absolute"
          });
        },
        stop: function(event, ui) {
          $(ui.helper).removeClass("shadow");
          $(ui.helper).addClass("w-100");
          $(".griffinforms-app-formlayout-rowcolumn").removeClass("griffinforms-fe-droppable");
        }
      });
    }
    ';
  }

  private function getReusableFieldsJs()
  {
    if (empty($_GET['form_id'])) {
      echo '
      const form_id = $(".griffinforms-app-formlayout-form").attr("data-gf-itemid");
      ';
    } else {
      echo '
      const form_id = ' . absint($_GET['form_id']) . ';';
    }

    echo '
    $("#' . esc_js($this->getHtmlId('reusable-fields-tab')) . '").click(function() {
      getReusableFields(limit = 20);
    });

    document.addEventListener("form-html-received", () => {
      getReusableFields();
    });

    function getReusableFields(limit = 20) {
      
    const fieldData = {
          "action": "getReusableFields",
          "form_id": form_id,
          "limit": limit
      };

      $.post(ajaxurl, fieldData, function(response) {
          response = JSON.parse(response);
          
          if (response.success) {
            $("#' . esc_js($this->getHtmlId('reusable-fields-tab-pane')) . '").children(".row").html(response.html);
            makeFieldPillsDraggable();
            setReusableFieldsHeight();
          } else {
            statusbarMsg("failure", response.msg);
          }

      });
    }
    ';
  }

  /**
   * Returns the HTML notice indicating that there are no reusable fields.
   *
   * @return string
   */
  private function getNoReusableFieldsNotice() {
      $notice  = '<div class="col-12">';
      $notice .= '<div class="gf-notice mt-4">';
      $notice .= __('No reusable fields available or all available fields are already used in this form. (Reusable fields are fields that you can create once and reuse in multiple forms.)', 'griffinforms-form-builder');
      $notice .= '</div>';
      $notice .= '</div>';
      return $notice;
  }

  /**
  * Retrieves reusable fields via an AJAX call.
  *
  * If there are no reusable fields, it returns a notice with instructions.
  *
  * @return void
  */
  public function getReusableFields()
  {
    $limit = isset($_POST['limit']) ? sanitize_text_field(wp_unslash($_POST['limit'])) : 0;
    $fields = $this->sql->getReusableFields($limit);

    if ($fields === false) {
        global $wpdb;
        $this->response['success'] = false;
        $this->response['msg'] = $wpdb->last_error;
    } else {
        $form_id = isset($_POST['form_id']) ? sanitize_text_field(wp_unslash($_POST['form_id'])) : 0;
        $html = $this->reusableFieldsHtml($fields, $form_id);
        $this->response['success'] = true;
        $this->response['msg'] = __('Fields updated successfully.', 'griffinforms-form-builder');

        if (empty($html['html'])) {
            $this->response['html'] = $this->getNoReusableFieldsNotice();
        } else {
            $this->response['html'] = $html['html'];
        }
    }

    echo wp_json_encode($this->response);
    wp_die();
  }

  /**
   * Generates the HTML for displaying reusable field pills.
   *
   * Filters out fields already used in the form to avoid duplicates.
   *
   * @param array $fields  List of available reusable fields.
   * @param int|string $form_id  Current form ID to check existing fields against.
   * @return array  Contains generated HTML and list of field IDs.
   */
  private function reusableFieldsHtml($fields, $form_id)
  {
    $html = '';
    $field_ids = [];

    $existing_fields = $this->sql->fieldsInForm($form_id);

    foreach ($fields as $field) {
        $field_ids[] = $field->id;
        $css_class = 'gf-app-reusable-field-pill gf-app-field-pill';

        // Skip rendering if the field is already used in the form.
        // Ensure strict type-safe comparison by casting both to string.
        if (!in_array((string) $field->id, array_map('strval', $existing_fields), true)) {
            if (empty($field->name)) {
                $field->name = $this->config->getFriendlyName('field') . '-' . $field->id;
            }

            $html .= '<div class="col-md-12">';
            $html .= '<div class="' . esc_attr($css_class) . ' text-start bg-light py-3 px-3 rounded-1 d-flex justify-content-start align-items-center" ';
            $html .= 'id="' . esc_attr($this->getHtmlId($field->id . '-field-pill')) . '" ';
            $html .= 'data-gf-itemid="' . esc_attr($field->id) . '">';

            // Place the icon inside the pill container
            ob_start();
            $this->fieldTypeIcon($field->field_type);
            $html .= ob_get_clean();

            $placeholder = \GriffinForms\Admin\App\Html\Elements\ShimmerPlaceholder::getInstance();

            $html .= '<div class="small ms-2" style="font-weight:500; letter-spacing: 0.5px;">' . esc_html($field->name) . '</div>';
            $html .= '<div class="ms-2 spinner-border spinner-border-sm visually-hidden" role="status">';
            $html .= '<span class="visually-hidden">Loading...</span>';
            $html .= '</div>';
            $html .= '</div>';
            $html .= '</div>';
        }
    }

    return ['html' => $html, 'field_ids' => $field_ids];
  }

  private function fieldTypeIcon($field_type)
  {
      static $checked_icons = [];

      $icon_file = 'griffinforms_icon_' . $field_type . '.svg';
      $icon_path = $this->config->getRootPath() . 'admin/images/field-icons/' . $icon_file;
      $icon_url  = $this->config->getRootUrl() . 'admin/images/field-icons/' . $icon_file;
      $fallback_url = $this->config->getRootUrl() . 'admin/images/field-icons/griffinforms_icon_fallback.svg';

      // Check and cache whether the icon file exists
      if (!isset($checked_icons[$field_type])) {
          $checked_icons[$field_type] = file_exists($icon_path);
      }

      $final_url = $checked_icons[$field_type] ? $icon_url : $fallback_url;

      echo '<img height="18" src="' . esc_url($final_url) . '" alt="' . esc_attr($field_type) . '" class="gf-app-field-icon" />';
  }

  public function __construct()
  {
      $this->setAll();
      add_action('wp_ajax_getReusableFields', array($this, 'getReusableFields'));
  }
}
