import { useEngagementMedium, useLazyQuery, useMutation, useParentValue, useProgramId, useQuery, useRefreshDispatcher, useUserIdentity, } from "@saasquatch/component-boilerplate";
import { useRef, useState } from "@saasquatch/universal-hooks";
import { gql } from "graphql-request";
import { REFERRAL_CODES_NAMESPACE, SET_CODE_COPIED, } from "../sqm-referral-codes/useReferralCodes";
const MAX_EDITS = 5;
const CHARACTER_LIMIT = 15;
const MIN_CHARACTERS = 3;
const MessageLinkQuery = gql `
  query ($programId: ID) {
    user: viewer {
      ... on User {
        shareLink(programId: $programId)
      }
    }
  }
`;
const WIDGET_ENGAGEMENT_EVENT = gql `
  mutation loadEvent($eventMeta: UserAnalyticsEvent!) {
    createUserAnalyticsEvent(eventMeta: $eventMeta)
  }
`;
const ADD_SHARE_LINK_CODE = gql `
  mutation ($addShareLinkCodeInput: AddShareLinkCodeInput!) {
    addShareLinkCode(addShareLinkCodeInput: $addShareLinkCodeInput) {
      linkCode {
        linkCode
        shortUrl
        referralCode {
          code
        }
      }
    }
  }
`;
const VALIDATE_LINK_CODE = gql `
  query validateLinkCode($linkCode: String!) {
    validateLinkCode(linkCode: $linkCode) {
      valid
      invalidReason
    }
  }
`;
const GET_LINK_DOMAIN = gql `
  query getLinkDomain {
    tenantSettings {
      primaryLinkDomain {
        host
      }
    }
  }
`;
const SHARE_LINK_EDIT_COUNT = gql `
  query shareLinkEditCount {
    viewer {
      ... on User {
        shareLinkCodes {
          totalCount
          data {
            isVanity
          }
        }
      }
    }
  }
`;
function parseShareUrl(url) {
  try {
    const parsed = new URL(url);
    return {
      url: parsed.origin + parsed.pathname,
      domain: parsed.origin + "/",
      path: parsed.pathname.slice(1),
    };
  }
  catch {
    return { url, domain: url, path: "" };
  }
}
export function useShareLink(props) {
  var _a, _b, _c, _d, _e, _f, _g;
  const { programId = useProgramId() } = props;
  const user = useUserIdentity();
  const engagementMedium = useEngagementMedium();
  const contextData = useParentValue(REFERRAL_CODES_NAMESPACE);
  const { data, refetch } = useQuery(MessageLinkQuery, { programId }, !(user === null || user === void 0 ? void 0 : user.jwt) || !!props.linkOverride || (contextData === null || contextData === void 0 ? void 0 : contextData.shareLink) !== undefined);
  const [sendLoadEvent] = useMutation(WIDGET_ENGAGEMENT_EVENT);
  const [setCopied] = useMutation(SET_CODE_COPIED);
  const [addShareLinkCode, { loading: isSaving }] = useMutation(ADD_SHARE_LINK_CODE);
  const [validateLinkCode] = useLazyQuery(VALIDATE_LINK_CODE);
  const { refresh } = useRefreshDispatcher();
  const { data: linkDomainData } = useQuery(GET_LINK_DOMAIN, {}, !(user === null || user === void 0 ? void 0 : user.jwt) || !props.allowCustomization);
  const { data: editCountData, refetch: refetchEditCount } = useQuery(SHARE_LINK_EDIT_COUNT, {}, !(user === null || user === void 0 ? void 0 : user.jwt) || !props.allowCustomization);
  const { url: copyString, domain: domainPrefix, path: pathSuffix, } = parseShareUrl((_b = ((contextData === null || contextData === void 0 ? void 0 : contextData.shareLink) || ((_a = data === null || data === void 0 ? void 0 : data.user) === null || _a === void 0 ? void 0 : _a.shareLink))) !== null && _b !== void 0 ? _b : 
  // Shown during loading
  "...");
  const [open, setOpen] = useState(false);
  const [isEditing, setIsEditing] = useState(false);
  const [editValue, setEditValue] = useState("");
  const [validationError, setValidationError] = useState(null);
  const [isValidating, setIsValidating] = useState(false);
  const debounceTimerRef = useRef(undefined);
  const latestValidationValueRef = useRef("");
  const hasPrimaryLinkDomain = ((_c = linkDomainData === null || linkDomainData === void 0 ? void 0 : linkDomainData.tenantSettings) === null || _c === void 0 ? void 0 : _c.primaryLinkDomain) != null;
  const customizeDisabled = !hasPrimaryLinkDomain;
  const vanityCount = (_g = (_f = (_e = (_d = editCountData === null || editCountData === void 0 ? void 0 : editCountData.viewer) === null || _d === void 0 ? void 0 : _d.shareLinkCodes) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.filter((code) => code.isVanity).length) !== null && _g !== void 0 ? _g : 0;
  const editCount = vanityCount;
  const editsRemaining = Math.max(0, MAX_EDITS - editCount);
  const limitReached = editsRemaining <= 0;
  function mapErrorCodeToInfo(errorCode) {
    if (!errorCode)
      return null;
    const errorMap = {
      EXISTING_CODE_CONFLICT: {
        code: "EXISTING_CODE_CONFLICT",
        title: props.linkTakenErrorTitle,
        description: props.linkTakenErrorDescription,
      },
      INVALID_CHARACTER: {
        code: "INVALID_CHARACTER",
        title: props.invalidCharactersErrorTitle,
        description: props.invalidCharactersErrorDescription,
      },
      BLOCKED_WORD: {
        code: "BLOCKED_WORD",
        title: props.restrictedWordsErrorTitle,
        description: props.restrictedWordsErrorDescription,
      },
    };
    return errorMap[errorCode];
  }
  async function onClick() {
    if (contextData) {
      await setCopied({ referralCode: contextData.referralCode });
      contextData.refresh();
    }
    // Should well supported: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard#browser_compatibility
    // Only if called from a user-initiated event
    navigator.clipboard.writeText(copyString);
    setOpen(true);
    setTimeout(() => setOpen(false), props.tooltiplifespan);
    sendLoadEvent({
      eventMeta: {
        programId,
        id: user === null || user === void 0 ? void 0 : user.id,
        accountId: user === null || user === void 0 ? void 0 : user.accountId,
        type: "USER_REFERRAL_PROGRAM_ENGAGEMENT_EVENT",
        meta: {
          engagementMedium,
          shareMedium: "DIRECT",
        },
      },
    });
  }
  function onCustomizeClick() {
    if (limitReached || customizeDisabled)
      return;
    setIsEditing(true);
    setEditValue(editCount === 0 ? "" : pathSuffix);
    setValidationError(null);
  }
  function onEditValueChange(value) {
    const trimmed = value.slice(0, CHARACTER_LIMIT);
    setEditValue(trimmed);
    setValidationError(null);
    latestValidationValueRef.current = trimmed;
    if (debounceTimerRef.current)
      clearTimeout(debounceTimerRef.current);
    if (!trimmed || trimmed.length < MIN_CHARACTERS) {
      setIsValidating(false);
      return;
    }
    setIsValidating(true);
    debounceTimerRef.current = setTimeout(async () => {
      var _a, _b;
      const requestedValue = trimmed;
      try {
        const result = await validateLinkCode({ linkCode: requestedValue });
        // Discard stale responses if the user has continued typing
        if (latestValidationValueRef.current !== requestedValue)
          return;
        if (!((_a = result === null || result === void 0 ? void 0 : result.validateLinkCode) === null || _a === void 0 ? void 0 : _a.valid)) {
          const reason = (_b = result === null || result === void 0 ? void 0 : result.validateLinkCode) === null || _b === void 0 ? void 0 : _b.invalidReason;
          setValidationError(mapErrorCodeToInfo(reason));
        }
      }
      catch {
        // Validation query failed — don't block the user
        if (latestValidationValueRef.current !== requestedValue)
          return;
      }
      if (latestValidationValueRef.current === requestedValue) {
        setIsValidating(false);
      }
    }, 500);
  }
  async function onSave() {
    var _a, _b;
    if (!editValue ||
      editValue.length < MIN_CHARACTERS ||
      validationError ||
      isValidating)
      return;
    try {
      await addShareLinkCode({
        addShareLinkCodeInput: {
          userId: user === null || user === void 0 ? void 0 : user.id,
          accountId: user === null || user === void 0 ? void 0 : user.accountId,
          programId,
          linkCode: editValue,
          makeShareLinkCodePrimaryForReferralCode: true,
        },
      });
      setIsEditing(false);
      await Promise.all([refetch(), refetchEditCount()]);
      refresh();
    }
    catch (e) {
      const errorCode = (_a = e === null || e === void 0 ? void 0 : e.extensions) === null || _a === void 0 ? void 0 : _a.code;
      setValidationError((_b = mapErrorCodeToInfo(errorCode)) !== null && _b !== void 0 ? _b : {
        code: null,
        title: props.saveErrorTitle,
        description: (e === null || e === void 0 ? void 0 : e.message) || props.saveErrorDescription,
      });
    }
  }
  function onCancel() {
    setIsEditing(false);
    setEditValue("");
    setValidationError(null);
    setIsValidating(false);
    latestValidationValueRef.current = "";
    if (debounceTimerRef.current)
      clearTimeout(debounceTimerRef.current);
  }
  return {
    copyTextViewProps: {
      ...props,
      onClick,
      open,
      copyString,
    },
    minCharactersText: props.minCharactersText,
    allowCustomization: props.allowCustomization,
    customizeLinkLabel: props.customizeLinkButtonLabel,
    saveLabelText: props.saveLabelText,
    savingLabelText: props.savingLabelText,
    cancelLabelText: props.cancelLabelText,
    editLabelText: props.editLabelText,
    charactersRemainingText: props.charactersRemainingText,
    validatingLabelText: props.validatingLabelText,
    isEditing,
    editValue,
    domainPrefix,
    editsRemaining,
    maxEdits: MAX_EDITS,
    limitReached,
    validationError,
    isValidating,
    isSaving,
    characterLimit: CHARACTER_LIMIT,
    minCharacters: MIN_CHARACTERS,
    charactersRemaining: CHARACTER_LIMIT - editValue.length,
    editLimitText: props.editLimitText,
    editLimitReachedText: props.editLimitReachedText,
    supportLinkText: props.supportLinkText,
    customizeDisabled,
    customizeDisabledTooltip: props.customizeDisabledTooltip,
    onCustomizeClick,
    onEditValueChange,
    onSave,
    onCancel,
  };
}
