import { useLocale, usePaginatedQuery, useProgramId, useQuery, 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:useRewardsTable");
export const CSS_NAMESPACE = "sqm-rewards-table";
const GET_REWARDS = gql `
  query getRewards(
    $limit: Int!
    $offset: Int!
    $rewardFilter: RewardFilterInput
    $locale: RSLocale
  ) {
    viewer {
      ... on User {
        id
        rewards(
          limit: $limit
          offset: $offset
          filter: $rewardFilter
          sortBy: { field: "dateCreated", order: DESC }
        ) {
          totalCount
          count
          data {
            meta {
              status
              integration {
                name
              }
              message
              customMeta
            }
            id
            type
            value
            unit
            name
            dateGiven
            dateCreated
            dateExpires
            dateCancelled
            dateRedeemed
            dateScheduledFor
            fuelTankCode
            fuelTankType
            currency
            prettyValue(locale: $locale)
            prettyValueNumber: prettyValue(
              formatType: NUMBER_FORMATTED
              locale: $locale
            )
            prettyAvailableNumber: prettyAvailableValue(
              formatType: NUMBER_FORMATTED
              locale: $locale
            )
            prettyRedeemedNumber: prettyRedeemedCredit(
              formatType: NUMBER_FORMATTED
              locale: $locale
            )
            programId
            program {
              name
            }
            partnerFundsTransfer {
              id
              status
              dateScheduled
              dateCreated
              dateTransferred
            }
            statuses
            pendingReasons
            cancelledReason
            globalRewardKey
            programRewardKey
            rewardSource
            prettyRedeemedCredit(locale: $locale)
            prettyAssignedCredit(locale: $locale)
            prettyAvailableValue(locale: $locale)
            exchangedRewardRedemptionTransaction {
              id
              creditRedeemed
              prettyRedeemedCredit(locale: $locale)
              unit
              dateRedeemed
            }
            referral {
              id
              dateModerated
              referrerUser {
                id
                firstName
                lastName
              }
              referredUser {
                id
                firstName
                lastName
              }
              fraudData {
                moderationStatus
                autoModerationStatus
                manualModerationStatus
              }
            }

            rewardRedemptionTransactions {
              data {
                exchangedRewards {
                  data {
                    prettyValue(locale: $locale)
                    type
                    fuelTankCode
                    globalRewardKey
                  }
                }
              }
            }
          }
        }
      }
    }
  }
`;
const GET_IMPACT_TAX = gql `
  query getImpactTax {
    viewer {
      ... on User {
        id
        impactConnection {
          connected
          taxHandlingEnabled
          publisher {
            requiredTaxDocumentType
            currentTaxDocument {
              status
              type
              dateCreated
            }
            withdrawalSettings {
              paymentMethod
            }
            payoutsAccount {
              hold
              holdReasons
              balance
            }
          }
        }
      }
    }
  }
`;
export function useRewardsTable(props, emptyElement, loadingElement) {
  var _a, _b, _c;
  const user = useUserIdentity();
  const programIdContext = useProgramId();
  const locale = useLocale();
  // Default to context, overriden by props
  const resolvedProgramId = (_a = props.programId) !== null && _a !== void 0 ? _a : programIdContext;
  const programId = resolvedProgramId === "GLOBAL" ? null : resolvedProgramId;
  const rewardFilter = {
    userId_eq: user === null || user === void 0 ? void 0 : user.id,
    accountId_eq: user === null || user === void 0 ? void 0 : user.accountId,
    // If no program ID, shows all programs
    ...(programId
      ? programId === "classic"
        ? { programId_exists: false }
        : { programId_eq: programId }
      : {}),
  };
  const [content, setContent] = useReducer((state, next) => ({
    ...state,
    ...next,
  }), {
    columns: [],
    rows: [],
    loading: false,
    page: 0,
  });
  const { data: impactTaxData, loading: taxLoading } = useQuery(GET_IMPACT_TAX, {}, !(user === null || user === void 0 ? void 0 : user.jwt));
  const { envelope: rewardsData, states, callbacks, } = usePaginatedQuery(GET_REWARDS, (data) => { var _a; return (_a = data === null || data === void 0 ? void 0 : data.viewer) === null || _a === void 0 ? void 0 : _a.rewards; }, {
    limit: props.perPage,
    offset: 0,
  }, {
    rewardFilter,
    locale,
  }, !(user === null || user === void 0 ? void 0 : user.jwt));
  const tick = useRerenderListener();
  const components = useChildElements();
  const data = rewardsData === null || rewardsData === void 0 ? void 0 : rewardsData.data;
  const taxConnection = (_b = impactTaxData === null || impactTaxData === void 0 ? void 0 : impactTaxData.viewer) === null || _b === void 0 ? void 0 : _b.impactConnection;
  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 (r) => {
      const cellPromise = columnComponents === null || columnComponents === void 0 ? void 0 : columnComponents.map(async (c) => tryMethod(c, () => c.renderCell(r, { locale, taxConnection }, 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 });
    rewardsData && getComponentData(components);
  }, [rewardsData, components, tick]);
  const isEmpty = !((_c = content === null || content === void 0 ? void 0 : content.rows) === null || _c === void 0 ? void 0 : _c.length) && !(data === null || data === void 0 ? void 0 : data.length);
  const show = 
  // 1 - Loading if loading
  states.loading || content.loading || taxLoading
    ? "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));
  }
}
