import { useEffect, useMemo, useState } from 'react';

import type ApiError from '~/lib/errors/ApiError';
import type { CustomLinkUnavailableError } from '~/lib/songwhipApi/customPageLinks';
import type {
  CustomLinksDialogRenderStage,
  ServiceLinksFormValues,
} from './types';

import { ItemTypes } from '~/lib/songwhipApi/types';
import removeUndefinedKeys from '~/lib/utils/removeUndefinedKeys';
import locales from '~/locales/fragments/customLinksDialog';
import {
  isDefaultDomainId,
  resolveDefaultDomainFromId,
} from '~/src/lib/customDomain';
import { resolveServiceDataFromUrl } from '~/src/lib/getServiceDisplayData';
import { useI18nStatic } from '~/src/lib/i18n';
import { useTracker } from '~/src/lib/tracker/useTracker';
import { addCustomPageLinkAction } from '~/src/store/lib/customPageLinks';
import { useDispatch } from '~/src/store/redux';
import Box from '../Box';
import Clickable from '../Clickable';
import { DialogBoxHeader } from '../DialogBox/DialogBoxHeader';
import ErrorText from '../ErrorText';
import Form from '../Form';
import Loading from '../Loading';
import { useAppAlert, useAppToast } from '../NextApp/lib/CoreUi';
import { useScroller } from '../Scroller2';
import Sticky from '../Sticky';
import Text from '../Text';
import { EditLinkSection, ParamSection, ServiceSection } from './components';
import { DEFAULT_CHANNELS_OPTIONS, DEFAULT_MEDIUM_OPTIONS } from './constants';
import { resolveCustomLinkItem } from './lib/resolveCustomLinkItem';
import { useCustomLinksDialogContext } from './useCustomLinksDialogContext';

export const AddServiceLinkStage: CustomLinksDialogRenderStage = ({
  setStage,
  paddingX,
  paddingY,
}) => {
  const { t, tx } = useI18nStatic<'customLinksDialog'>(locales);
  const scroller = useScroller();

  const [selectedService, setSelectedService] = useState<string>();
  const [isLoading, setIsLoading] = useState(false);

  const serviceMissingPlaceholder = !selectedService
    ? t('serviceLinks.disabledPlaceholder')
    : undefined;

  const { trackEvent } = useTracker();
  const appToast = useAppToast();
  const appAlert = useAppAlert();
  const dispatch = useDispatch();

  const { item, debug, account, accountIsLoading } =
    useCustomLinksDialogContext();

  const defaultPath = useMemo(() => {
    if (!selectedService) return '';

    const path = (
      selectedService.startsWith('@')
        ? selectedService.replace('@', '')
        : resolveServiceDataFromUrl(selectedService).key
    ).toLowerCase();

    const serviceLinksCount = (item.customLinks ?? []).reduce(
      (count, { redirectTo }) => (redirectTo ? count + 1 : count),
      0
    );

    return serviceLinksCount > 0 ? `${path}${serviceLinksCount + 1}` : path;
  }, [selectedService]);

  useEffect(() => {
    scroller?.setScrollTop(0);
  }, []);

  return (
    <Form<ServiceLinksFormValues>
      testId="addCustomPageLinkForm"
      onSubmit={async ({ values }) => {
        try {
          setIsLoading(true);

          const customDomainId = Number(values.domainId);
          const defaultDomain = resolveDefaultDomainFromId(customDomainId);

          let artistId: number | undefined;

          // If a default domain is selected, the CustomLink won't be linked to a CustomDomain,
          // but instead will be linked to an Artist.
          if (isDefaultDomainId(customDomainId)) {
            artistId = item.type === ItemTypes.ARTIST ? item.id : item.artistId;
          }

          await dispatch(
            addCustomPageLinkAction({
              ...resolveCustomLinkItem(item),
              customDomainId: artistId ? undefined : customDomainId,
              artistId,
              defaultDomain,
              // add leading slash and clean tailing slash
              path: `/${values.path.replace(/\/$/, '')}`,
              redirectTo: values.redirectTo,
              params: removeUndefinedKeys({
                utm_source: values.utmSource || undefined,
                utm_medium: values.utmMedium || undefined,
              }),
            })
          );

          trackEvent({
            type: 'create-custom-link',
            linkType: 'service',
            utmSource: values.utmSource,
            utmMedium: values.utmMedium,
          });

          setStage('default');

          appToast({
            text: t('createServiceLink.successToast'),
          });
        } catch (e) {
          const error = e as ApiError | CustomLinkUnavailableError;
          let content = <ErrorText error={error} />;

          if (error.code === 'LINK_UNAVAILABLE') {
            content = <Text isParagraph>{tx('linkUnavailableError')}</Text>;
          }

          debug('api error', error);

          setSelectedService(undefined);
          setIsLoading(false);

          appAlert({
            title: 'Error',
            content,
          });
        }
      }}
    >
      <Sticky top={0} zIndex={2}>
        <DialogBoxHeader
          title={t('serviceLinksSection.title')}
          onBackClick={() => setStage('default')}
          renderRight={({ textProps }) => (
            <Clickable
              isDisabled={accountIsLoading || isLoading || !selectedService}
              testId="addLinkSubmit"
              isSubmit
            >
              <Text {...textProps}>{t('submit')}</Text>
            </Clickable>
          )}
        />
      </Sticky>
      <Box padding={`0.2rem ${paddingX} ${paddingY}`}>
        {(() => {
          if (isLoading || accountIsLoading || !account) {
            return <Loading height="5rem" />;
          }

          return (
            <Box flexColumn style={{ gap: paddingY }}>
              <ServiceSection
                onChange={({ value }) => {
                  setSelectedService(value);
                }}
              />
              <EditLinkSection
                initialPath={defaultPath}
                label={t('serviceLinks.linkTitle')}
                placeholder={serviceMissingPlaceholder}
                isDisabled={!selectedService}
                renderDescription={
                  !selectedService
                    ? () => t('serviceLinks.disabledLinkHint')
                    : undefined
                }
              />
              <ParamSection
                testId="sourceSelect"
                name="utmSource"
                title="channel"
                placeholder={
                  serviceMissingPlaceholder ?? t('utmParams.channelPlaceholder')
                }
                label={t('utmParams.channelLabel')}
                description={t('utmParams.serviceLinkChannelDescription')}
                configKey="utmSources"
                options={DEFAULT_CHANNELS_OPTIONS}
                searchPlaceholder={t('utmParams.searchChannelPlaceholder')}
                isDisabled={!selectedService}
              />
              <ParamSection
                testId="mediumSelect"
                name="utmMedium"
                title="medium"
                placeholder={
                  serviceMissingPlaceholder ?? t('utmParams.mediumPlaceholder')
                }
                label={t('utmParams.mediumLabel')}
                description={t('utmParams.serviceLinkMediumDescription')}
                configKey="utmMediums"
                options={DEFAULT_MEDIUM_OPTIONS}
                searchPlaceholder={t('utmParams.searchMediumPlaceholder')}
                isDisabled={!selectedService}
              />
            </Box>
          );
        })()}
      </Box>
    </Form>
  );
};
