import { useLocale, usePaginatedQuery, useUserIdentity, } from "@saasquatch/component-boilerplate";
import { useEffect, useReducer } from "@saasquatch/universal-hooks";
import { h } from "@stencil/core";
import debugFn from "debug";
import { gql } from "graphql-request";
import { useRerenderListener } from "../../tables/re-render";
import { useChildElements } from "../../tables/useChildElements";
import { generateUserError } from "../sqm-referral-table/useReferralTable";
const debug = debugFn("sq:useInvoiceTable");
export const CSS_NAMESPACE = "sqm-invoice-table";
export const GET_INVOICES = gql `
  query getUserTaxInfo($limit: Int!, $offset: Int!) {
    user: viewer {
      ... on User {
        impactConnection {
          connected
          publisher {
            invoices(limit: $limit, offset: $offset) {
              data {
                id
                dateCreated
                totalAmount
                totalVatAmount
                downloadUrl
                currency
              }
              totalCount
            }
          }
        }
      }
    }
  }
`;
export function useInvoiceTable(props, emptyElement, loadingElement) {
  var _a;
  const user = useUserIdentity();
  const locale = useLocale();
  const [content, setContent] = useReducer((state, next) => ({
    ...state,
    ...next,
  }), {
    columns: [],
    rows: [],
    loading: false,
    page: 0,
  });
  const { envelope: invoicesData, states, callbacks, } = usePaginatedQuery(GET_INVOICES, (data) => { var _a, _b, _c; return (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.user) === null || _a === void 0 ? void 0 : _a.impactConnection) === null || _b === void 0 ? void 0 : _b.publisher) === null || _c === void 0 ? void 0 : _c.invoices; }, {
    limit: props.perPage,
    offset: 0,
  }, {}, !(user === null || user === void 0 ? void 0 : user.jwt));
  const tick = useRerenderListener();
  const components = useChildElements();
  const data = invoicesData === null || invoicesData === void 0 ? void 0 : invoicesData.data;
  async function getComponentData(components) {
    // filter out loading and empty states from columns array
    const columnComponents = components.filter((component) => component.slot !== "loading" && component.slot !== "empty");
    // get the column titles (renderLabel is asynchronous)
    const columnsPromise = columnComponents === null || columnComponents === void 0 ? void 0 : columnComponents.map(async (c) => tryMethod(c, () => c.renderLabel()));
    // get the column cells (renderCell is asynchronous)
    const cellsPromise = data === null || data === void 0 ? void 0 : data.map(async (invoice) => {
      var _a, _b, _c;
      // TODO: probably going to pass in values as named by graphql
      const invoiceData = {
        earnings: `${invoice.currency}${((_a = invoice.totalAmount) === null || _a === void 0 ? void 0 : _a.toFixed(2)) || "0.00"}`,
        indirectTax: `${invoice.currency}${((_b = invoice.totalVatAmount) === null || _b === void 0 ? void 0 : _b.toFixed(2)) || "0.00"}`,
        dateCreated: invoice.dateCreated,
        invoiceId: invoice.id,
        netEarnings: `${invoice.currency}${((_c = (invoice.totalAmount - invoice.totalVatAmount)) === null || _c === void 0 ? void 0 : _c.toFixed(2)) || "0.00"}`,
        downloadUrl: invoice.downloadUrl,
      };
      const cellPromise = columnComponents === null || columnComponents === void 0 ? void 0 : columnComponents.map(async (c) => tryMethod(c, () => c.renderCell(invoiceData, { locale }, h)));
      const cells = (await Promise.all(cellPromise));
      return cells;
    });
    const rows = cellsPromise && (await Promise.all(cellsPromise)).filter((i) => i);
    setContent({ rows });
    const columns = columnsPromise &&
      (await Promise.all(columnsPromise));
    // Set the content to render and finish loading components
    setContent({ columns, loading: false, page: states.currentPage });
  }
  useEffect(() => {
    setContent({ loading: true });
    invoicesData && getComponentData(components);
  }, [invoicesData, components, tick]);
  const isEmpty = !((_a = content === null || content === void 0 ? void 0 : content.rows) === null || _a === void 0 ? void 0 : _a.length) && !(data === null || data === void 0 ? void 0 : data.length);
  const show = 
  // 1 - Loading if loading
  states.loading || content.loading
    ? "loading"
    : // 2 - Empty if empty
      isEmpty
        ? "empty"
        : // 3 - Then show rows
          "rows";
  return {
    states: {
      hasNext: states.currentPage < states.pageCount - 1,
      hasPrev: states.currentPage > 0,
      show,
      namespace: CSS_NAMESPACE,
    },
    data: {
      textOverrides: {
        showLabels: !props.hideLabels,
        prevLabel: props.prevLabel,
        moreLabel: props.moreLabel,
      },
      hiddenColumns: props.hiddenColumns,
      smBreakpoint: props.smBreakpoint,
      mdBreakpoint: props.mdBreakpoint,
    },
    elements: {
      columns: content.columns,
      rows: content.rows,
      emptyElement,
      loadingElement,
    },
    callbacks: {
      nextPage: () => {
        callbacks.setCurrentPage(states.currentPage + 1);
      },
      prevPage: () => {
        callbacks.setCurrentPage(states.currentPage - 1);
      },
    },
  };
}
export async function tryMethod(c, callback) {
  const tag = c.tagName.toLowerCase();
  await customElements.whenDefined(tag);
  let labelPromise;
  try {
    labelPromise = callback();
  }
  catch (e) {
    // renderLabel did not return a promise, so this method probably doesn't exist
    // therefore, we IGNORE the label
    debug("label promise failed", e);
    return h("span", null);
  }
  try {
    return await labelPromise;
  }
  catch (e) {
    // The column returned a promise, and that promise failed.
    // This should not happen so we fail fast
    debug("Error rendering label", e);
    const userError = generateUserError(e);
    return (h("details", null,
      h("summary", null, "Error"),
      userError));
  }
}
