function createTable(
  endpoint,
  tableId,
  headers,
  maxHeight,
  sortable,
  valueId,
  selectableRows,
  filterTargets,
  defaultFirstSelected,
) {
  async function fetchDataForTable(query) {
    try {
      const apiEndpoint = `${apiURL}/${endpoint}?${query}`;
      const response = await fetch(apiEndpoint);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      const fetchedData = await response.json();
      data = fetchedData;
      generateTable(data);
    } catch (error) {
      console.error("Fetching data failed:", error);
    }
  }

  function generateTable(data) {
    const jsonTableContainer = document.getElementById(`${tableId}-container`);
    jsonTableContainer.className = "jsonTableContainer";
    jsonTableContainer.innerHTML = "";
    jsonTableContainer.style.maxHeight = maxHeight;

    tableHeaderNames = Object.values(headers);
    tableHeaderKeys = Object.keys(headers);

    const table = document.createElement("table");
    table.id = tableId;
    const thead = document.createElement("thead");
    const tbody = document.createElement("tbody");
    const headerRow = document.createElement("tr");
    tableHeaderNames.forEach((header) => {
      const th = document.createElement("th");
      th.textContent = header;
      headerRow.appendChild(th);
    });
    thead.appendChild(headerRow);
    table.appendChild(thead);

    for (const key in data) {
      const row = document.createElement("tr");
      row.value = data[key][valueId];
      tableHeaderKeys.forEach((columnName) => {
        const td = document.createElement("td");
        const div = document.createElement("div");
        div.id = "scrollable";
        div.textContent = data[key][columnName];
        td.appendChild(div);
        row.appendChild(td);
        tbody.appendChild(row);
      });
    }
    table.appendChild(thead);
    table.appendChild(tbody);
    jsonTableContainer.appendChild(table);


    if (sortable == true) {
      table.className = "sortable";
      sorttable.makeSortable(document.getElementById(tableId));
    }

    if (selectableRows === "multi" || selectableRows === "single") {
      const rows = table.getElementsByTagName("tr");
      for (let i = 1; i < rows.length; i++) {
        rows[i].addEventListener("click", function() {
          if (selectableRows === "multi") {
            this.classList.toggle("selected");
            if (this.classList.contains("selected")) {
              const event = new CustomEvent("filterChange", {
                detail: {
                  filterId: valueId,
                  filterValue: this.value,
                  filterActions: ["selected"],
                  filterTargets: filterTargets,
                },
              });
              document.dispatchEvent(event);
            } else {
              const event = new CustomEvent("filterChange", {
                detail: {
                  filterId: valueId,
                  filterValue: this.value,
                  filterActions: ["deselected"],
                  filterTargets: filterTargets,
                },
              });
              document.dispatchEvent(event);
            }
          } else if (selectableRows === "single") {
            const event = new CustomEvent("filterChange", {
              detail: {
                filterId: valueId,
                filterValue: this.value,
                filterActions: ["selected"],
                filterTargets: filterTargets,
              },
            });
            document.dispatchEvent(event);

            if (this.classList.contains("selected")) {
              this.classList.remove("selected");
            } else {
              for (let j = 1; j < rows.length; j++) {
                rows[j].classList.remove("selected");
              }
              this.classList.add("selected");
            }
          }
        });
        if (defaultFirstSelected == true) {
          if (i == 1) {
            rows[i].classList.add("selected");
            const event = new CustomEvent("filterChange", {
              detail: {
                filterId: valueId,
                filterValue: rows[i].value,
                filterActions: ["selected"],
                filterTargets: filterTargets,
              },
            });
            document.dispatchEvent(event);
          }
        }
      }
    }

  }

  document.addEventListener("filterChange", function(event) {
    tableId = document.getElementById(tableId).id;
    if (event.detail.filterTargets.includes(tableId)) {
      query = queryConstructor();
      fetchDataForTable(query);
    }
  });

  let query = queryConstructor();
  fetchDataForTable(query);
}

function createChart(
  chart,
  chatId,
  endpoint,
  xAxisField,
  yAxisField,
  chartType,
  xAxisType,
  scaleChart = true,
  formatValueDecimalPlaces = null,
) {
  async function fetchDataForChart(query, valueId) {
    try {
      const apiEndpoint = `${apiURL}/${endpoint}?${query}`;
      const response = await fetch(apiEndpoint);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      const fetchedData = await response.json();
      const newData = fetchedData.reduce((acc, item) => {
        const objectId = item[valueId];
        if (!acc[objectId]) {
          acc[objectId] = [];
        }
        acc[objectId].push([item[xAxisField], item[yAxisField]]);
        return acc;
      }, {});
      chartData = { ...chartData, ...newData };
      updateChart();
    } catch (error) {
      console.error("Fetching data failed:", error);
    }
  }

  function updateChart() {
    let chartDataMap = new Map();
    for (let objectId in chartData) {
      chartDataMap.set(objectId, chartData[objectId]);
    }

    var option = {
      tooltip: {
        ...tooltip,
        valueFormatter(value, index) {
          return formatValueDecimalPlaces == null
            ? value
            : nFormatter(value, formatValueDecimalPlaces);
        },
      },
      xAxis: {
        type: xAxisType,
      },
      yAxis: {
        scale: scaleChart,
        type: "value",
      },
      series: Array.from(chartDataMap.entries()).map(([name, data]) => ({
        name,
        type: chartType,
        data,
        showSymbol: false,
      })),
    };
    chart.setOption(option, true);
  }

  // listen for filter events for this target
  document.addEventListener("filterChange", function(event) {
    eventDetail = event.detail;
    if (eventDetail.filterActions.includes("refresh")) {
      chartData = [];
      updateChart();
    } else {
      if (eventDetail.filterTargets.includes(chatId)) {
        if (eventDetail.filterActions.includes("selected")) {
          valueId = eventDetail.filterId;
          let selectedRow = {
            [valueId]: eventDetail.filterValue,
          };
          query = queryConstructor(selectedRow);

          fetchDataForChart(query, valueId);
        } else {
          delete chartData[eventDetail.filterValue];
          updateChart();
        }
      }
    }
  });
}

document.addEventListener("DOMContentLoaded", function() {
  chartData = [];
  let chartDom = document.getElementById("bitcoin-business-growth-chart");
  let myChart = echarts.init(chartDom);

  const filterPeriods = {"7 day": 7, "28 day": 28, "365 day": 365, "2 years": 730, "5 years": 1826, "10 years": 3652, "all time": 10000};
  dropDownFilter("days_ago_dropdown_filter", "days_ago", ["bitcoin-business-growth-chart", "bitcoin-business-growth-table"], filterPeriods, "365 day")

  createTable(
    endpoint = "bitcoin_business_growth_percent_diff",
    tableId = "bitcoin-business-growth-table",
    headers = {
      'country_name': 'Country',
      'date_range': 'Date Range',
      'first_value': 'Previous #',
      'last_value': 'Current #',
      'difference': 'Diff',
      'percent_difference': '% Diff'
    },
    maxHeight = "400px",
    sortable = true,
    valueId = "country_name",
    selectableRows = "multi",
    filterTargets = "bitcoin-business-growth-chart",
    defaultFirstSelected = true
  )

  createChart(
    chart = myChart,
    chartId = "bitcoin-business-growth-chart",
    endpoint = "bitcoin_business_growth_timeseries",
    xAxisField = "date",
    yAxisField = "cumulative_value",
    chartType = "line",
    xAxisType = "category",
  );
});