// Formatter mappings keyed by column name — extend as needed.
// All datetime columns from the API are listed here.
const DOMAIN_COLUMN_FORMATTERS = {
    "r_h_disp":                  { formatter: "highlightFormatter", search: false, sortable: true },
    "status":                    { formatter: "domainStatusFormatter" },
    "registrar":                 { formatter: "registrarFormatter" },
    "registry_expiry":           { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d",       newformat: "YYYY-MMM-DD"        } },
    "registrar_expiry":          { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d",       newformat: "YYYY-MMM-DD"        } },
    "created_on":                { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d",       newformat: "YYYY-MMM-DD"        } },
    "last_update":               { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d",       newformat: "YYYY-MMM-DD"        } },
    "ssl_valid_from":            { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d",       newformat: "YYYY-MMM-DD"        } },
    "ssl_valid_to":              { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d",       newformat: "YYYY-MMM-DD"        } },
    "added_from_profile_at":     { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "added_on":                  { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "cookie_expiry":             { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "dotdb_checked_at":          { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "estibot_checked_at":        { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "home_page_checked_at":      { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "home_page_modified":        { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "ip_whois_at":               { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "manual_edited_at":          { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "ping_checked_at":           { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "primary_whois_checked_at":  { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "rootdns_checked_at":        { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "secondary_whois_checked_at":{ formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "ssl_checked_at":            { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "subdomains_autofound_at":   { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "subdomains_checked_at":     { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
    "websites_checked_at":       { formatter: "date", sorttype: "date", formatoptions: { srcformat: "Y-m-d H:i:s", newformat: "YYYY-MMM-DD H:i:s" } },
};

// Fallback widths used only when domainColumns has no saved width for a column.
const DOMAIN_COLUMN_FIELDTYPE_WIDTHS = {
    "datetime": 200,
    "date":     160,
    "float":    120,
    "integer":  100,
    "boolean":   80,
    "text":     200,
    "string":   150,
};

// Default column set for the domain portfolio grid.
const DEFAULT_REQUESTED_COLUMNS = [
    "ctrl",
    "d.selling_price",
    "d.dotdb_exact_matches",
    "d.minimum_offer",
    "d.primary_whois_checked_at",
    "d.registry_expiry",
    "d.registrar",
    "d.registrar_expiry",
    "d.created_on",
    "d.last_update",
    "d.status",
    "d.tld",
    "d.ip",
    "d.ns1",
    "d.ns2",
    "d.visual_domain",
    "member_of",  // virtual column — always appended last in defaults
];

///////////////////////////////////////////////////////////////////////////////
// Virtual column: member_of
// Displays the categories a domain belongs to.
// Data is populated via _domainMembershipMap in portfolio.js after ajaxData.
// formatter: "memberOfFormatter" is defined in portfolio.js.
///////////////////////////////////////////////////////////////////////////////

const MEMBER_OF_COLUMN = {
    name:      "member_of",
    label:     "Member Of",
    width:     180,
    classes:   "dtcell member-of-cell",
    virtual:   true,       // excluded from API column list
    hidden:    false,
    sortable:  false,      // no backing real column yet
    search:    false,
    editable:  false,
    move:      true,
    resize:    true,
    formatter: "memberOfFormatter",
};

///////////////////////////////////////////////////////////////////////////////
// Virtual column: ns_summary
// Displays all nameservers for a domain as pills.
// Data is read directly from d.ns1–d.ns8 in rowData.
// formatter: "nameserversFormatter" is defined in portfolio.js.
// Hidden backing columns d.ns1–d.ns8 are injected automatically by
// buildColumnDefsFromDomainColumns when this column is present.
///////////////////////////////////////////////////////////////////////////////

const NS_SUMMARY_COLUMN = {
    name:      "ns_summary",
    label:     "Nameservers",
    width:     220,
    classes:   "dtcell ns-summary-cell",
    virtual:   true,
    hidden:    false,
    sortable:  false,
    search:    false,
    editable:  false,
    move:      true,
    resize:    true,
    formatter: "nameserversFormatter",
};

///////////////////////////////////////////////////////////////////////////////
// User-controllable virtual columns
// Referenced by columns.js to populate the column picker panel with virtual
// columns that are not in domainColumns API metadata.
// Add new user-facing virtual columns here as they are created.
///////////////////////////////////////////////////////////////////////////////

const KNOWN_USER_VIRTUAL_COLUMNS = [
    { name: "member_of", label: "Member Of" },
	 { name: "ns_summary", label: "Nameservers" },
];

/**
 * Returns the default grid column definitions for the domain portfolio table.
 */
function getDefaultDomainGridColumns(domainColumns) {
    return buildColumnDefsFromDomainColumns(domainColumns, DEFAULT_REQUESTED_COLUMNS);
}

/**
 * Returns the width for a column.
 */
function getDefaultColumnWidth(meta) {
    if (meta.width) return meta.width;
    return DOMAIN_COLUMN_FIELDTYPE_WIDTHS[meta.fieldtype] || 150;
}

/**
 * Builds a grid column definition array for the domain portfolio table.
 *
 * Four columns are always present regardless of requestedColumns:
 *   - dt_ser_num  : row serial number
 *   - cb          : checkbox
 *   - d.r_h_disp  : highlight/alert indicator
 *   - d.domain    : domain name
 *
 * "ctrl"      in requestedColumns injects the row refresh control button at that position.
 * "member_of" in requestedColumns injects the MEMBER_OF_COLUMN virtual column at that position.
 * All entries in requestedColumns are processed in order — position is fully preserved.
 *
 * @param {Object} domainColumns    - Column metadata from the API
 * @param {Array}  requestedColumns - Optional ordered list of column names
 * @returns {Array} Column definition array suitable for DataTableView
 */
function buildColumnDefsFromDomainColumns(domainColumns, requestedColumns = null) {

    const PREFIX_COLUMNS = [
        { name: "dt_ser_num", label: "#", width: { default: 65 }, resize: true },
        { name: "cb",         label: "",  width: { default: 24 }, resize: false, type: "cb" },
        {
            label:     "!",
            width:     50,
            name:      "d.r_h_disp",
            classes:   "dtcell r-h-disp-cell tc-icon",
            move:      false,
            formatter: "highlightFormatter",
            fixed:     true,
            hidden:    false,
            sortable:  true,
            search:    false,
            editable:  false,
        },
        {
            label:       "Domain",
            width:       domainColumns?.domain?.width || 231,
            name:        "d.domain",
            classes:     "dtcell domain-cell",
            minwidth:    100,
            move:        false,
            editoptions: { readonly: true, size: 35 },
            hidden:      false,
            sortable:    true,
            search:      true,
            editable:    true,
        },
    ];

    const CONTROL_COLUMN = {
        label:       "⚙️",
        name:        "d.r_h_disp",
        classes:     "dtcell control-cell btn-lookup-domain-row",
        width:       70,
        move:        false,
        formatter:   "controlFormatter",
        editoptions: { readonly: true, size: 35 },
        hidden:      false,
        sortable:    false,
        search:      false,
        editable:    false,
        resize:      false,
        virtual:     true,
        always_on:   true,  // excluded from column picker panel
    };

    const prefixNames = new Set(PREFIX_COLUMNS.map(c => c.name));

    // Build a lookup of all known user-controllable virtual columns by name
    // so any virtual can be resolved by name during the ordered pass below.
    const virtualColDefs = {};
    if (typeof KNOWN_USER_VIRTUAL_COLUMNS !== "undefined") {
        KNOWN_USER_VIRTUAL_COLUMNS.forEach(def => {
            // Find the full column definition constant by matching MEMBER_OF_COLUMN etc.
            // We rely on the global MEMBER_OF_COLUMN (and future equivalents) being
            // accessible here since this function is in the same file.
            if (def.name === "member_of") virtualColDefs["member_of"] = MEMBER_OF_COLUMN;
			if (def.name === "ns_summary") virtualColDefs["ns_summary"] = NS_SUMMARY_COLUMN;
        });
    }

    let domainCols = [];

    if (requestedColumns && Array.isArray(requestedColumns)) {
        // Walk requestedColumns in order — preserves user-defined column position
        requestedColumns.forEach(c => {
            if (c === "ctrl") {
                domainCols.push(CONTROL_COLUMN);
                return;
            }

            // User-controllable virtual column (bare name, no "d." prefix)
            if (virtualColDefs[c]) {
                domainCols.push(virtualColDefs[c]);
                return;
            }

            // Regular API column — strip "d." prefix if present
            const bare = c.startsWith("d.") ? c.substring(2) : c;
            if (prefixNames.has(`d.${bare}`)) return; // skip mandatory cols
            if (!(bare in domainColumns))      return; // not in API metadata

            const meta         = domainColumns[bare];
            const formatterDef = DOMAIN_COLUMN_FORMATTERS[bare] || {};
            domainCols.push({
                name:        `d.${bare}`,
                label:       meta.label || bare,
                width:       getDefaultColumnWidth(meta),
                classes:     `dtcell ${bare.replace(/_/g, "-")}-cell`,
                hidden:      false,
                sortable:    true,
                search:      true,
                move:        true,
                editable:    meta.editable === 1,
                editoptions: { size: 35 },
                ...formatterDef,
            });
        });
    } else {
        // No requestedColumns — ctrl first, then all gridview===1 API cols, then virtuals
        domainCols.push(CONTROL_COLUMN);

        Object.entries(domainColumns)
            .filter(([, meta]) => meta.gridview === 1)
            .filter(([colName]) => !prefixNames.has(`d.${colName}`))
            .forEach(([colName, meta]) => {
                const formatterDef = DOMAIN_COLUMN_FORMATTERS[colName] || {};
                domainCols.push({
                    name:        `d.${colName}`,
                    label:       meta.label || colName,
                    width:       getDefaultColumnWidth(meta),
                    classes:     `dtcell ${colName.replace(/_/g, "-")}-cell`,
                    hidden:      false,
                    sortable:    true,
                    search:      true,
                    move:        true,
                    editable:    meta.editable === 1,
                    editoptions: { size: 35 },
                    ...formatterDef,
                });
            });

        // Append all known user-controllable virtuals at the end
        Object.values(virtualColDefs).forEach(def => domainCols.push(def));
    }
	
	// If ns_summary virtual column is present, inject hidden d.ns1–d.ns8
    // so getColumnNames() fetches them from the API without rendering them.
    const allCols     = [...PREFIX_COLUMNS, ...domainCols];
    const hasNsSummary = allCols.some(c => c.name === "ns_summary");

	if (hasNsSummary) {
        const NS_BACKING_COLS = [
            "d.ns1","d.ns2","d.ns3","d.ns4",
            "d.ns5","d.ns6","d.ns7","d.ns8"
        ];

        // Build set of explicitly requested ns columns
        const explicitNsCols = new Set(
            requestedColumns
                ? NS_BACKING_COLS.filter(c => requestedColumns.includes(c))
                : []
        );

        NS_BACKING_COLS.forEach(function(nsCol) {
            const bare        = nsCol.substring(2);
            const existingIdx = allCols.findIndex(c => c.name === nsCol);

            if (existingIdx !== -1) {
                // Only force hidden if NOT explicitly requested by the user
                if (!explicitNsCols.has(nsCol)) {
                    allCols[existingIdx] = { ...allCols[existingIdx], hidden: true };
                }
            } else {
                if (!domainColumns || !(bare in domainColumns)) return;
                // Only inject as hidden if not explicitly requested
                if (!explicitNsCols.has(nsCol)) {
                    allCols.push({
                        name   : nsCol,
                        label  : "",
                        width  : { default: 0 },
                        hidden : true,
                        virtual: false,
                    });
                }
            }
        });
        return allCols;
    }

    return [...PREFIX_COLUMNS, ...domainCols];
}