import { downloadCsv } from "../services/csv";
import escapeHtml from "../services/dom";
import normalizeSearchValue from "../services/search";
import createExplorerModal from "./explorer-modal";

function resolveExplorerRowStateClass(datasetKey, row) {
  const errorCount = Number(row.error_count_raw ?? 0);
  const avgDuration = Number(row.avg_duration_raw ?? 0);
  const callCount = Number(row.request_count_raw ?? 0);

  if (errorCount > 0) {
    return "no-technical-explorer__row no-technical-explorer__row--danger";
  }

  if (datasetKey === "external_requests") {
    if (avgDuration >= 800) {
      return "no-technical-explorer__row no-technical-explorer__row--warning";
    }

    return "no-technical-explorer__row no-technical-explorer__row--success";
  }

  if (avgDuration >= 600 || callCount >= 100) {
    return "no-technical-explorer__row no-technical-explorer__row--warning";
  }

  return "no-technical-explorer__row no-technical-explorer__row--success";
}

export default function initTechnicalInsightsExplorer(
  container,
  explorerSettings,
) {
  if (!explorerSettings || !explorerSettings.datasets) {
    return;
  }

  const wrappers = container.querySelectorAll("[data-no-technical-explorer]");
  const modal = createExplorerModal(container);

  wrappers.forEach((wrapper) => {
    if (wrapper.dataset.technicalExplorerReady === "true") {
      return;
    }

    const datasetButtons = wrapper.querySelectorAll(
      "[data-no-explorer-dataset-button]",
    );
    const searchInput = wrapper.querySelector("[data-no-explorer-search]");
    const pageSizeInput = wrapper.querySelector("[data-no-explorer-page-size]");
    const descriptionTarget = wrapper.querySelector(
      "[data-no-explorer-description]",
    );
    const headTarget = wrapper.querySelector("[data-no-explorer-head]");
    const bodyTarget = wrapper.querySelector("[data-no-explorer-body]");
    const emptyTarget = wrapper.querySelector("[data-no-explorer-empty]");
    const paginationSummary = wrapper.querySelector(
      "[data-no-explorer-pagination-summary]",
    );
    const previousButton = wrapper.querySelector(
      "[data-no-explorer-pagination-prev]",
    );
    const nextButton = wrapper.querySelector(
      "[data-no-explorer-pagination-next]",
    );
    const exportFilteredButton = wrapper.querySelector(
      "[data-no-explorer-export-filtered]",
    );
    const exportFullButton = wrapper.querySelector(
      "[data-no-explorer-export-full]",
    );
    const flushButton = wrapper.querySelector("[data-no-explorer-flush]");
    const flushHelp = wrapper.querySelector("[data-no-explorer-flush-help]");

    const datasetKeys = Object.keys(explorerSettings.datasets);
    if (!datasetKeys.length) {
      return;
    }

    const state = {
      activeDatasetKey: datasetKeys[0],
      query: "",
      sortKey: "",
      sortDirection: "desc",
      page: 1,
      pageSize: Number(pageSizeInput?.value || 10),
    };

    const getActiveDataset = () =>
      explorerSettings.datasets[state.activeDatasetKey] || null;

    const getFilteredRows = (dataset) => {
      const query = normalizeSearchValue(state.query);
      let rows = Array.isArray(dataset.rows) ? [...dataset.rows] : [];

      if (query) {
        rows = rows.filter((row) =>
          dataset.search_keys.some((key) =>
            normalizeSearchValue(row[key]).includes(query),
          ),
        );
      }

      const sortKey =
        state.sortKey || dataset.default_sort?.key || dataset.columns[0]?.key;
      let sortDirection = dataset.default_sort?.direction || "desc";

      if (state.sortKey) {
        sortDirection = state.sortDirection;
      }

      rows.sort((left, right) => {
        const leftValue = left[`${sortKey}_raw`] ?? left[sortKey] ?? "";
        const rightValue = right[`${sortKey}_raw`] ?? right[sortKey] ?? "";

        if (typeof leftValue === "number" && typeof rightValue === "number") {
          return sortDirection === "asc"
            ? leftValue - rightValue
            : rightValue - leftValue;
        }

        const collator = new Intl.Collator(undefined, {
          numeric: true,
          sensitivity: "base",
        });

        return sortDirection === "asc"
          ? collator.compare(String(leftValue), String(rightValue))
          : collator.compare(String(rightValue), String(leftValue));
      });

      return rows;
    };

    const getPaginatedRows = (rows) => {
      const start = (state.page - 1) * state.pageSize;
      return rows.slice(start, start + state.pageSize);
    };

    let renderExplorer = () => {};

    const renderHeaders = (dataset) => {
      headTarget.innerHTML = dataset.columns
        .map((column) => {
          let sortDirection = "";

          if (state.sortKey === column.key) {
            sortDirection = state.sortDirection;
          } else if (dataset.default_sort?.key === column.key) {
            sortDirection = dataset.default_sort.direction;
          }

          const sortClass = sortDirection
            ? ` no-technical-explorer__sort-button--${sortDirection}`
            : "";

          return `<th><button type="button" class="no-technical-explorer__sort-button${sortClass}" data-no-explorer-sort-key="${column.key}">${column.label}</button></th>`;
        })
        .join("");

      headTarget
        .querySelectorAll("[data-no-explorer-sort-key]")
        .forEach((button) => {
          button.addEventListener("click", () => {
            const nextKey = button.getAttribute("data-no-explorer-sort-key");

            if (state.sortKey === nextKey) {
              state.sortDirection =
                state.sortDirection === "asc" ? "desc" : "asc";
            } else {
              state.sortKey = nextKey;
              state.sortDirection = "desc";
            }

            state.page = 1;
            renderExplorer();
          });
        });
    };

    const renderRows = (dataset, rows, filteredRows) => {
      if (!filteredRows.length) {
        bodyTarget.innerHTML = "";
        emptyTarget.hidden = false;
        emptyTarget.textContent = dataset.empty_message;
        return;
      }

      emptyTarget.hidden = true;
      bodyTarget.innerHTML = rows
        .map(
          (row, index) => `
        <tr class="${resolveExplorerRowStateClass(state.activeDatasetKey, row)}" data-no-explorer-row-index="${index}">
          ${dataset.columns
            .map((column, columnIndex) => {
              const value = escapeHtml(row[column.key] ?? "—");

              if (columnIndex === 0 && row.detail) {
                return `<td><button type="button" class="no-technical-explorer__row-link" data-no-explorer-open-detail="${index}">${value}</button></td>`;
              }

              if (column.key === "action_label" && row.action_url) {
                return `<td><a class="button button--small button--primary" href="${escapeHtml(row.action_url)}">${value}</a></td>`;
              }

              return `<td>${value}</td>`;
            })
            .join("")}
        </tr>
      `,
        )
        .join("");

      bodyTarget
        .querySelectorAll("[data-no-explorer-open-detail]")
        .forEach((button) => {
          button.addEventListener("click", () => {
            const rowIndex = Number(
              button.getAttribute("data-no-explorer-open-detail"),
            );
            const selectedRow = rows[rowIndex] || null;

            if (selectedRow?.detail && modal) {
              modal.open(selectedRow.detail);
            }
          });
        });
    };

    const renderPagination = (filteredRows) => {
      const totalRows = filteredRows.length;
      const startRow =
        totalRows === 0 ? 0 : (state.page - 1) * state.pageSize + 1;
      const endRow = Math.min(totalRows, state.page * state.pageSize);
      const totalPages = Math.max(1, Math.ceil(totalRows / state.pageSize));

      paginationSummary.textContent = `${startRow}-${endRow} of ${totalRows}`;
      previousButton.disabled = state.page <= 1;
      nextButton.disabled = state.page >= totalPages;
    };

    renderExplorer = () => {
      const dataset = getActiveDataset();
      if (!dataset) {
        return;
      }

      descriptionTarget.textContent = dataset.description || "";

      if (searchInput) {
        searchInput.placeholder =
          dataset.search_placeholder || Drupal.t("Search");
      }

      datasetButtons.forEach((button) => {
        const isActive =
          button.getAttribute("data-no-explorer-dataset-button") ===
          state.activeDatasetKey;
        button.setAttribute("aria-pressed", isActive ? "true" : "false");
      });

      const filteredRows = getFilteredRows(dataset);
      const totalPages = Math.max(
        1,
        Math.ceil(filteredRows.length / state.pageSize),
      );

      if (state.page > totalPages) {
        state.page = totalPages;
      }

      const paginatedRows = getPaginatedRows(filteredRows);

      renderHeaders(dataset);
      renderRows(dataset, paginatedRows, filteredRows);
      renderPagination(filteredRows);

      exportFilteredButton.onclick = () => {
        downloadCsv(
          `${dataset.export_key || state.activeDatasetKey}-filtered.csv`,
          dataset.columns,
          filteredRows,
        );
      };

      exportFullButton.onclick = () => {
        downloadCsv(
          `${dataset.export_key || state.activeDatasetKey}-full.csv`,
          dataset.columns,
          dataset.rows || [],
        );
      };

      if (flushButton && flushHelp) {
        flushButton.disabled = false;
        flushButton.removeAttribute("aria-disabled");
        flushHelp.textContent = dataset.flush_help || "";

        flushButton.onclick = () => {
          if (!dataset.actions?.flush) {
            return;
          }

          // eslint-disable-next-line no-alert
          const confirmed = window.confirm(
            [
              Drupal.t(
                'Are you sure you want to invalidate the dashboard cache for "@label"?',
                { "@label": dataset.label },
              ),
              Drupal.t("This action does not delete raw traces or raw spans."),
            ].join("\n\n"),
          );

          if (!confirmed) {
            return;
          }

          flushButton.disabled = true;

          fetch(dataset.actions.flush, {
            method: "POST",
            headers: {
              "X-Requested-With": "XMLHttpRequest",
            },
          })
            .then((response) => {
              if (!response.ok) {
                throw new Error(Drupal.t("Unable to flush the dataset cache."));
              }

              return response.json();
            })
            .then(() => {
              window.location.reload();
            })
            .catch(() => {
              flushButton.disabled = false;
            });
        };
      }
    };

    datasetButtons.forEach((button) => {
      button.addEventListener("click", () => {
        state.activeDatasetKey = button.getAttribute(
          "data-no-explorer-dataset-button",
        );
        state.page = 1;
        state.sortKey = "";
        state.sortDirection = "desc";
        renderExplorer();
      });
    });

    searchInput?.addEventListener("input", (event) => {
      state.query = event.currentTarget.value;
      state.page = 1;
      renderExplorer();
    });

    pageSizeInput?.addEventListener("change", (event) => {
      state.pageSize = Number(event.currentTarget.value || 10);
      state.page = 1;
      renderExplorer();
    });

    previousButton?.addEventListener("click", () => {
      if (state.page > 1) {
        state.page -= 1;
        renderExplorer();
      }
    });

    nextButton?.addEventListener("click", () => {
      state.page += 1;
      renderExplorer();
    });

    renderExplorer();
    wrapper.dataset.technicalExplorerReady = "true";
  });
}
