/*!
 * customfields.js — Bootstrap 5 modernized + flexible column layouts
 * Layout modes:
 *   2          = Two columns (default)
 *   1          = One column full width
 *   '1-wide'   = One per row, half-width (left-aligned). Use your portrait mixin to make 100% on mobile.
 */
(function (w, $) {
  if (!$) throw new Error("customfields.js requires jQuery");

  var customFields = (function () {
    var allFieldsDisabled = true;
    var selectListeners = {};
    var clickListeners = {};
    var unique_id = 0;

    // Layout state
    var _defaultColumns = 2;      // 2 | 1 | '1-wide'
    var _activeColumns  = _defaultColumns;
    var _rowInitialized = false;
    var _rowEl          = null;   // jQuery row element
    var _rendererRef    = null;   // last renderer
    var _select2Width   = 'resolve';

    // ---------- helpers ----------
    function safe(val) { return (val === undefined || val === null) ? '' : String(val); }

    function labelBS5(forId, text, hidden) {
      var style = hidden ? ' style="display:none;"' : '';
      return '<label for="' + forId + '" class="form-label fw-semibold"' + style + '>' + safe(text) + '</label>';
    }

    function popoverWrapStart(name, description) {
      return '<span data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-html="true" data-bs-placement="top" title="' +
             safe(name) + '" data-bs-content="' + safe(description) + '">';
    }

    function ensureRow(renderer) {
      if (_rowInitialized && _rowEl && _rowEl.length) return;
      _rowEl = $('<div class="row custom-fields-row"></div>');
      _rowInitialized = true;
      _rendererRef = renderer || _rendererRef;
      if (typeof _rendererRef === 'function') _rendererRef(_rowEl);
      else $('body').append(_rowEl); // last resort
    }

    function colWrap(innerHtml, hidden) {
      var display = hidden ? ' style="display:none;"' : '';
      // '1-wide' = left-aligned half width
      if (_activeColumns === '1-wide') {
        return '<div class="col-12"' + display + '>' +
                 '<div class="form-elem w-100" style="max-width:50%;">' + innerHtml + '</div>' +
               '</div>';
      }
      var colClass = (_activeColumns === 1) ? 'col-12' : 'col-sm-6';
      return '<div class="' + colClass + '"' + display + '><div class="form-elem">' + innerHtml + '</div></div>';
    }

    function colWrapForced12(innerHtml, hidden) {
      var display = hidden ? ' style="display:none;"' : '';
        return '<div class="col-12"' + display + '>' +
                 '<div class="form-elem w-75">' + innerHtml + '</div>' +
               '</div>';
    }

    function appendToRow($html) {
      ensureRow();
      _rowEl.append($html);
    }

    function applySelect2IfAvailable(selector, field) {
      if (jQuery().select2) {
        $(selector).select2({ minimumResultsForSearch: 10, width: _select2Width });
        if (field && field.ishidden) $(selector).next('.select2-container').hide(); // v4 container
      }
    }

    function ceLang(str) {
      return (w.clientexec && typeof w.clientexec.lang === 'function') ? w.clientexec.lang(str) : str;
    }

    // ---------- public API ----------
    return {
      setColumns: function (n) {
        _defaultColumns = (n === 1 || n === '1-wide') ? n : 2;
      },
      getColumns: function () { return _defaultColumns; },

      /**
       * Load multiple fields.
       * @param {Array} fields
       * @param {Function} renderer - function($el){ append to your container }
       * @param {Function} postload
       * @param {Boolean} unique - if truthy, adds unique suffix to control ids
       * @param {Number|'1-wide'} columnsOverride
       */
      load: function (fields, renderer, postload, unique, columnsOverride) {
        allFieldsDisabled = true;
        _activeColumns = (columnsOverride !== undefined && columnsOverride !== null) ? columnsOverride : _defaultColumns;
        _rowInitialized = false; _rowEl = null; _rendererRef = renderer || null;

        ensureRow(renderer);
        var uniq = !!unique;
        for (var i = 0; i < fields.length; i++) this.getMarkup(fields[i], renderer, uniq, null, true);
        if (typeof postload === 'function') postload();
      },

      /**
       * Render a single field (ensures row exists if called directly).
       */
      getMarkup: function (f, renderer, unique, columnsOverride, _fromLoad) {
        if (!_fromLoad) {
          _activeColumns = (columnsOverride !== undefined && columnsOverride !== null) ? columnsOverride : _defaultColumns;
          ensureRow(renderer);
        }

        unique_id++;
        var isDisabled = !(f.ischangeable == 1);
        if (!isDisabled) allFieldsDisabled = false;

        var controlid = f.id;
        var createHiddenTypeField = false;
        if ($.isNumeric(f.id) || String(f.fieldtype) == '50') {
          controlid = 'CT_' + f.id;
          createHiddenTypeField = true;
        }

        f.field_name = controlid;
        f.field_id   = unique ? (controlid + '_' + unique_id) : controlid;
        f.name       = ceLang(f.name);

        switch (String(f.fieldtype)) {
          case '65': case '2': case '14': case '3': case '5': case '11': case '12': case '7':
          case '0':  case '54': this.renderTextField(controlid, f, isDisabled); break;
          case '47': this.renderVATField(controlid, f, isDisabled); break;
          case '13': this.renderEmailField(controlid, f, isDisabled); break;
          case '10': this.renderTextArea(controlid, f, isDisabled); break;
          case '15': this.renderDate(controlid, f, isDisabled); break;
          case '16': case '1': // yes/no
            f.dropdownoptions = [[0, "No"], [1, "Yes"]];
            // fallthrough
          case '8': case '30': case '6': case '4': case '9':
            this.renderDropDown(controlid, f, isDisabled); break;
          case '49': this.renderButton(controlid, f, isDisabled); break;
          case '52': this.renderHidden(controlid, f); break;
          case '50': this.renderHostname(controlid, f, isDisabled); break;
          case '55': this.renderNameserver(controlid, f, isDisabled); break;
          case '53': this.renderCheckBox(controlid, f, isDisabled); break;
          case 'subdomain': this.renderSubDomain(controlid, f, isDisabled); break;
          default: break;
        }

        if (createHiddenTypeField) {
          var hiddenField = {
            value: f.fieldtype, id: 'CTT_' + f.id, name: f.id, additional_class: 'customfield_hidden',
            field_name: null, field_id: null, ishidden: f.ishidden
          };
          hiddenField.field_name = hiddenField.id;
          hiddenField.field_id   = unique ? (hiddenField.id + '_' + unique_id) : hiddenField.id;
          this.renderHidden(hiddenField.id, hiddenField);
        }

        // listeners
        if (f.listener && f.listener.onclick) {
          clickListeners[controlid] = f.listener.onclick;
          $(document).off('click', '#' + controlid).on('click', '#' + controlid, function () { eval(clickListeners[this.id] + '()'); });
        }
        if (f.listener && f.listener.onselect) {
          selectListeners[controlid] = f.listener.onselect;
          $(document).off('change', '#' + controlid).on('change', '#' + controlid, function () { eval(selectListeners[this.id] + '()'); });
        }
      },

      // ---------- renderers (BS5 markup) ----------

      renderCheckBox: function (id, f, dis) {
        var required = (f.isrequired === true || f.isrequired == 1) ? ' data-parsley-mincheck="1" data-parsley-required="true"' : '';
        var html =
          '<div class="form-check">' +
            '<input class="form-check-input" id="' + id + '" name="' + f.id + '" type="checkbox" value="' + safe(f.value) + '"' +
              (dis ? ' disabled' : '') + required + '>' +
            '<label class="form-check-label" for="' + id + '">' + safe(f.name) + '</label>' +
          '</div>';
        appendToRow($(colWrap(html, !!f.ishidden)));
      },

      renderHidden: function (id, f) {
        var name = (typeof f.name === 'undefined') ? f.id : f.name;
        var label = '<span for="' + id + '" class="customfield_hidden" style="display:none;">' + name + '</span>';
        var field = '<input id="' + id + '" name="' + name + '" value="' + safe(f.value) + '" type="hidden">';
        ensureRow(); _rowEl.append(label + field); // keep DOM order but not in a grid column
      },

      renderButton: function (id, f, dis) {
        var btnClass = 'btn btn-primary';
        if (f.class) btnClass += ' ' + f.class;
        var html = '<button id="' + id + '" type="button" class="' + btnClass + '"' + '>' +
                     '<span>' + safe(ceLang(f.value)) + '</span>' +
                   '</button>';
        appendToRow($(colWrap(html, !!f.ishidden)));
      },

      renderDate: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var name   = safe(f.name);
        var displayVal = (f.value && f.value !== '' && f.value !== '00/00/0000') ? f.value : ceLang('No date selected');
        var label  = labelBS5(f.field_id, name, hidden);
        if (f.description) label = popoverWrapStart(name, f.description) + label + '</span>';

        var inputGroup =
          '<div class="input-group">' +
            '<input id="' + f.field_id + '" name="' + id + '" type="text" class="form-control disableDatePickerAutoLoad" value="' + safe(displayVal) + '" readonly' + (dis ? ' disabled' : '') + '>' +
            '<span class="input-group-text"><i class="bi bi-calendar"></i></span>' +
          '</div>';

        // maintain hidden type for legacy (if needed downstream)
        var arr = id.split('_');
        var ctt = (arr.length > 1) ? ("<input type='hidden' name='CTT_" + arr[1] + "' value='15'>") : '';

        appendToRow($(colWrap(label + inputGroup + ctt, hidden)));

        // init datepicker
        var df = (w.clientexec && w.clientexec.dateFormat === "d/m/Y") ? "dd/mm/yyyy" : "mm/dd/yyyy";
        $('#' + f.field_id).datepicker({ format: df, autoclose: true });
      },

      renderTextArea: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var name   = safe(f.name);
        var label  = labelBS5(id, name, hidden);
        if (f.description) label = popoverWrapStart(name, f.description) + label + '</span>';

        var required = (f.isrequired === true || f.isrequired == 1) ? ' data-parsley-required="true"' : '';
        var height   = (f.height && Number(f.height) > 0) ? ' style="min-height:' + Number(f.height) + 'px;"' : '';
        var field =
          '<textarea id="' + id + '" name="' + id + '" class="form-control disableSelect2AutoLoad"' + required + (dis ? ' disabled' : '') + height + '>' +
            safe(f.value) +
          '</textarea>';

        appendToRow($(colWrap(label + field, hidden)));
      },

      renderDropDown: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var showcheckboxes = (typeof f.showcheckboxes !== 'undefined') ? f.showcheckboxes : false;
        var showlabel      = (typeof f.showlabel      !== 'undefined') ? f.showlabel      : true;

        var name = safe(f.name);
        var desc = f.description;
        var label = showlabel ? labelBS5(f.field_id, name, hidden) : '';
        if (desc && !showcheckboxes) label = popoverWrapStart(name, desc) + label + '</span>';

        var options = '';
        var value_in_list = false;

        $.each(f.dropdownoptions || [], function (_, pair) {
          var val = pair[0], text = pair[1];
          var selected = (val == f.value) ? ' selected' : '';
          if (showcheckboxes) {
            options +=
                '<div class="form-check">' +
                '<input class="form-check-input" type="radio" name="' + id + '" id="' + id + '_' + val + '" value="' + val + '"' + selected + '>' +
                '<label class="form-check-label" for="' + id + '_' + val + '">' + text + '</label>' +
                '</div>';
          } else {
            options += "<option value='" + val + "'" + selected + ">" + text + "</option>";
          }
          if (selected) value_in_list = true;
        });

        if (!value_in_list && f.value !== "" && !showcheckboxes) {
          options += "<option value='" + f.value + "' selected>" + f.value + "</option>";
        }

        if (showcheckboxes) {
          var descBlock = desc ? '<div class="text-muted small mb-2">' + desc + '</div>' : '';
          appendToRow($(colWrap((showlabel ? labelBS5(id, name, hidden) : '') + descBlock + options, hidden)));
        } else {
          var req = (f.isrequired === true || f.isrequired == 1) ? ' data-parsley-required="true"' : '';
          var select =
              '<select id="' + f.field_id + '" name="' + id + '" class="form-select select2 type_' + f.fieldtype + ' disableSelect2AutoLoad"' + req + (dis ? ' disabled' : '') + '>' +
              options +
              '</select>';

          var field;
          if (typeof f.isquantity !== 'undefined' && f.isquantity === true) {
            field =
                label +
                '<div class="d-flex gap-2 align-items-end">' +
                '<div style="width:80px">' +
                '<label class="form-label" for="quantity_' + f.field_id + '">' + clientexec.lang("Quantity") + '</label>' +
                '<input type="number" min="0" class="form-control quantity type_' + f.fieldtype + '" id="quantity_' + f.field_id + '" name="quantity_' + id + '" value="' + f.quantity + '">' +
                '</div>' +
                '<div class="flex-grow-1">' +
                '<label class="form-label">' + clientexec.lang("Option") + '</label>' +
                select +
                '</div>' +
                '</div>' +
                '<div class="text-muted small mt-1">* ' + clientexec.lang("Prices will be multiplied by the quantity") + '</div>';
          } else {
            field = label + select;
          }

          appendToRow($(colWrap(field, hidden)));
          applySelect2IfAvailable('#' + f.field_id, f);
        }
      },


      renderEmailField: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var name   = safe(f.name);
        var value  = safe(f.value).replace(/"/g, '&quot;');

        var label  = labelBS5(id, name, hidden);
        if (f.description) label = popoverWrapStart(name, f.description) + label + '</span>';

        var req    = (f.isrequired === true || f.isrequired == 1) ? ' data-parsley-required="true"' : '';
        var vAttr  = f.validation_type ? (' data-type="' + f.validation_type + '"') : '';
        var type   = 'email';

        var field  =
          '<input data-parsley-type="email" id="' + id + '" name="' + id + '" type="' + type + '" class="form-control type_' + f.fieldtype + '"' +
          req + vAttr + (dis ? ' disabled' : '') + ' value="' + value + '">';

        appendToRow($(colWrap(label + field, hidden)));
      },
      renderTextField: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var name   = safe(f.name);
        var value  = safe(f.value).replace(/"/g, '&quot;');

        var label  = labelBS5(id, name, hidden);
        if (f.description) label = popoverWrapStart(name, f.description) + label + '</span>';

        var req    = (f.isrequired === true || f.isrequired == 1) ? ' data-parsley-required="true"' : '';
        var vAttr  = f.validation_type ? (' data-type="' + f.validation_type + '"') : '';
        var type   = f.is_password ? 'password' : 'text';

        var field  =
          '<input id="' + id + '" name="' + id + '" type="' + type + '" class="form-control type_' + f.fieldtype + '"' +
          req + vAttr + (dis ? ' disabled' : '') + ' value="' + value + '">';

        appendToRow($(colWrap(label + field, hidden)));
      },

      renderSubDomain: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var name   = safe(f.name);
        var label  = labelBS5(id, name, hidden);

        var tldOptions = '';
        (f.subdomains || []).forEach(function (tld) { tldOptions += '<option value="' + tld + '">' + tld + '</option>'; });

        var row =
          '<div class="row g-2 align-items-end">' +
            '<div class="col-md-8">' +
              '<input id="' + id + '" name="' + id + '" type="text" class="form-control" pattern="^([-0-9A-Za-z]+)$" data-parsley-required="true" onchange="validateSubDomain(\'' + id + '\');"' + (dis ? ' disabled' : '') + '>' +
            '</div>' +
            '<div class="col-md-4">' +
              '<div class="input-group">' +
                '<span class="input-group-text">.</span>' +
                '<select id="subdomaintld_' + id + '" name="subdomaintld_' + id + '" class="form-select" onchange="validateSubDomain(\'' + id + '\');">' +
                  tldOptions +
                '</select>' +
              '</div>' +
            '</div>' +
          '</div>';

        appendToRow($(colWrap(label + row, hidden)));
      },

      renderVATField: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var name   = safe(f.name);
        var label  = labelBS5(id, name, hidden);
        if (f.description) label = popoverWrapStart(name, f.description) + label + '</span>';

        var field =
          '<div class="input-group">' +
            '<span class="input-group-text" id="vat_country"></span>' +
            '<input id="' + id + '" name="' + id + '" type="text" class="form-control type_' + f.fieldtype + '" value="' + safe(f.value) + '"' + (dis ? ' disabled' : '') + '>' +
          '</div>' +
          '<div id="vat_validating" class="form-text text-muted d-none">' + ceLang("Validating...") + '</div>' +
          '<div id="vat_valid" class="form-text text-success d-none">' + ceLang("Valid VAT Number") + '</div>' +
          '<div id="vat_invalid" class="form-text text-danger d-none">' + ceLang("Invalid VAT Number") + '.&nbsp;<a href="javascript:validate_vat();">' + ceLang("Retry") + '</a></div>' +
          '<div id="vat_error" class="form-text text-warning d-none">' + ceLang("Unable to validate at the moment.") + '&nbsp;<a href="javascript:validate_vat();">' + ceLang("Retry") + '</a></div>';

        appendToRow($(colWrap(label + field, hidden)));
      },

      renderNameserver: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var html =
          labelBS5(id, safe(f.name), hidden) +
          '<div class="d-flex align-items-start gap-2">' +
            '<div class="flex-grow-1">' +
              '<input class="form-control nameserver" id="' + id + '" name="' + id + '" type="text" value="' + safe(f.value) + '"' + (dis ? ' disabled' : '') + '>' +
            '</div>' +
            '<div>' +
              '<button type="button" id="' + id + '_nameserverdelete" class="btn btn-outline-danger" onclick="nameservers_deleteaddress(this);">' + ceLang('Delete') + '</button>' +
            '</div>' +
          '</div>';
        appendToRow($(colWrap(html, hidden)));
      },

      renderHostname: function (id, f, dis) {
        var hidden = !!f.ishidden;
        var v = f.value || { hosttype: 'A', hostname: '', address: '' };
        function opt(val, sel) { return '<option value="' + val + '"' + (sel ? ' selected' : '') + '>' + val + '</option>'; }
        var options = ''
          + opt('A',    v.hosttype === 'A')
          + opt('AAAA', v.hosttype === 'AAAA')
          + opt('MXE',  v.hosttype === 'MXE')
          + opt('MX',   v.hosttype === 'MX')
          + opt('CNAME',v.hosttype === 'CNAME')
          + opt('URL',  v.hosttype === 'URL')
          + opt('FRAME',v.hosttype === 'FRAME')
          + opt('TXT',  v.hosttype === 'TXT');

var block =
  '<div class="mb-3 dns-entry-block">' +
    '<div class="mb-2">' +
      labelBS5('hostname_' + id, safe(f.name), false) +
    '</div>' +

    // Row for inputs + delete button
    '<div class="row g-2 align-items-stretch">' +

      // Hostname
      '<div class="col-md-3">' +
        '<input id="hostname_' + id + '" name="hostname_' + id + '" ' +
        'type="text" class="form-control" placeholder="Name" ' +
        'value="' + safe(v.hostname) + '"' + (dis ? ' disabled' : '') + '>' +
      '</div>' +

      // Record type
      '<div class="col-md-3">' +
        '<select id="hosttype_' + id + '" name="hosttype_' + id + '" ' +
        'class="form-select select2">' + options + '</select>' +
      '</div>' +

      // Address
      '<div class="col-md-3">' +
        '<input id="hostaddress_' + id + '" name="hostaddress_' + id + '" ' +
        'type="text" class="form-control" placeholder="Address" ' +
        'value="' + safe(v.address) + '"' + (dis ? ' disabled' : '') + '>' +
      '</div>' +

      // Delete button
      '<div class="col-md-3 d-flex">' +
        '<button type="button" id="' + id + '_hostdelete" ' +
          'class="btn btn-outline-danger w-100 h-100 text-nowrap"' +
          (dis ? ' disabled' : '') +
          ' onclick="hostrecords_deleteaddress(this);">' +
          ceLang("Delete") +
        '</button>' +
      '</div>' +

    '</div>' + // end row

  '</div>'; // end dns-entry-block




        appendToRow($(colWrapForced12(block, hidden)));
        if (typeof w.packagemanager !== "undefined") w.packagemanager.newhostrecordid++;
        else if (typeof w.hostinfo !== "undefined") w.hostinfo.newhostrecordid++;
        applySelect2IfAvailable('#hosttype_' + id, f);
      },

      // ---------- utilities ----------
      getAllFieldsDisabled: function () { return allFieldsDisabled; },
      getCustomFieldsAdded: function () { return []; },
      resetCustomFields: function () { /* noop in modern version */ }
    };
  })();

  // Expose globally for legacy inline references
  w.customFields = customFields;

})(window, window.jQuery);
