import { useEffect, useState } from 'react';

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

import { ItemTypes } from '~/lib/songwhipApi/types';
import removeUndefinedKeys from '~/lib/utils/removeUndefinedKeys';
import locales from '~/locales/fragments/customLinksDialog';
import {
  isDefaultDomainId,
  resolveDefaultDomainFromId,
  resolveDefaultDomainId,
} from '~/src/lib/customDomain';
import { useI18nStatic } from '~/src/lib/i18n';
import {
  deleteCustomPageLinkAction,
  editCustomPageLinkAction,
} from '~/src/store/lib/customPageLinks';
import { useDispatch } from '~/src/store/redux';
import Box from '../Box';
import { ConfirmButton } from '../Button/ConfirmButton';
import Clickable from '../Clickable';
import { DialogBoxHeader } from '../DialogBox/DialogBoxHeader';
import ErrorText from '../ErrorText';
import Form from '../Form';
import Loading from '../Loading';
import { useAppAlert, useAppConfirm, useAppToast } from '../NextApp/lib/CoreUi';
import { useScroller } from '../Scroller2';
import Sticky from '../Sticky';
import SwitchSetting from '../Switch/SwitchSetting';
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 EditServiceLinkStage = ({
  setStage,
  paddingX,
  paddingY,
  serviceLink,
}: Parameters<CustomLinksDialogRenderStage>[0] & {
  serviceLink: ServiceLink;
}) => {
  const { t, tx } = useI18nStatic<'customLinksDialog'>(locales);
  const scroller = useScroller();

  const [isLoading, setIsLoading] = useState(false);

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

  const appToast = useAppToast();
  const appAlert = useAppAlert();
  const appConfirm = useAppConfirm();
  const dispatch = useDispatch();

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

  return (
    <Form<ServiceLinksFormValues>
      testId="editServiceLinkForm"
      onSubmit={async ({ values }) => {
        const isConfirmed = await appConfirm({
          actionText: t('submit'),
          content: t('editServiceLink.saveConfirmDescription'),
          isDanger: false,
        });

        if (isConfirmed) {
          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(
              editCustomPageLinkAction({
                ...resolveCustomLinkItem(item),
                customLinkId: serviceLink.id,
                customDomainId: artistId ? undefined : customDomainId,
                artistId,
                defaultDomain,
                // add leading slash and clean tailing slash
                path: `/${values.path.replace(/\/$/, '')}`,
                isDefault: values.isDefault,
                redirectTo: values.redirectTo,
                params: removeUndefinedKeys({
                  utm_source: values.utmSource || undefined,
                  utm_medium: values.utmMedium || undefined,
                }),
              })
            );

            setStage('default');

            appToast({
              text: t('editServiceLink.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);
            setIsLoading(false);

            appAlert({
              title: 'Error',
              content,
            });
          }
        }
      }}
    >
      <Sticky top={0} zIndex={1}>
        <DialogBoxHeader
          title={t('editServiceLink.title')}
          onBackClick={() => setStage('default')}
          renderRight={({ textProps }) => (
            <Clickable
              isSubmit
              isDisabled={accountIsLoading || isLoading}
              testId="editLinkSubmit"
            >
              <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 initialServiceId={serviceLink.redirectTo} />
              <EditLinkSection
                initialPath={serviceLink.path.replace(/^\//, '')}
                initialDomainId={resolveDefaultDomainId(serviceLink)}
              />
              <ParamSection
                testId="sourceSelect"
                name="utmSource"
                title="channel"
                placeholder={t('utmParams.channelPlaceholder')}
                defaultValue={serviceLink.params?.utm_source}
                label={t('utmParams.channelLabel')}
                description={t('utmParams.serviceLinkChannelDescription')}
                configKey="utmSources"
                options={DEFAULT_CHANNELS_OPTIONS}
                searchPlaceholder={t('utmParams.searchChannelPlaceholder')}
              />
              <ParamSection
                testId="mediumSelect"
                name="utmMedium"
                title="medium"
                placeholder={t('utmParams.mediumPlaceholder')}
                defaultValue={serviceLink.params?.utm_medium}
                label={t('utmParams.mediumLabel')}
                description={t('utmParams.serviceLinkMediumDescription')}
                configKey="utmMediums"
                options={DEFAULT_MEDIUM_OPTIONS}
                searchPlaceholder={t('utmParams.searchMediumPlaceholder')}
              />
              {defaultFeature && (
                <SwitchSetting
                  testId="isDefaultToggle"
                  name="isDefault"
                  color="#eee"
                  title={t('editCustomLink.makeDefaultAction')}
                  defaultValue={serviceLink.isDefault ?? undefined}
                />
              )}
              <ConfirmButton
                enabled={false}
                testId="deleteServiceLink"
                text={t('delete')}
                onClick={async () => {
                  const isConfirmed = await appConfirm({
                    content: t('editServiceLink.deleteConfirmDescription'),
                    actionText: t('delete'),
                  });

                  if (isConfirmed) {
                    setIsLoading(true);

                    try {
                      await dispatch(
                        deleteCustomPageLinkAction({
                          ...resolveCustomLinkItem(item),
                          customLinkId: serviceLink.id,
                        })
                      );

                      setStage('default');

                      appToast({
                        text: t('linkDeleted'),
                      });
                    } catch (error) {
                      setIsLoading(false);

                      appAlert({
                        content: <ErrorText error={error} />,
                      });
                    }
                  }
                }}
              />
            </Box>
          );
        })()}
      </Box>
    </Form>
  );
};
