import { useCallback, useRef, useState } from 'react';

import type { MappedAccount } from '~/lib/songwhipApi/accounts/types';
import type { FC } from 'react';
import type {
  DialogBoxRenderContent,
  DialogBoxRenderHeader,
} from '../DialogBox';
import type { FormApi } from '../Form';
import type { CustomBrandFormProps } from './CustomBrandForm';

import locales from '~/locales/fragments/customBrandDialog';
import useIsLargeScreen from '~/src/hooks/useIsLargeScreen';
import { useI18nStatic } from '~/src/lib/i18n';
import {
  deleteCustomBrandApi,
  putCustomBrandApi,
} from '~/src/lib/songwhipApi/accounts/customBrands';
import { useTracker } from '../../lib/tracker/useTracker';
import Box from '../Box';
import Clickable from '../Clickable';
import DialogBox from '../DialogBox';
import { DialogBoxHeader } from '../DialogBox/DialogBoxHeader';
import { useAppToast } from '../NextApp/lib/CoreUi';
import Text from '../Text';
import CustomBrandForm from './CustomBrandForm';

interface CustomBrandDialogProps
  extends Pick<
    CustomBrandFormProps,
    | 'initialBrandName'
    | 'initialDomain'
    | 'initialDynamicColoring'
    | 'initialIconImage'
    | 'existingDomains'
  > {
  onClose: () => void;
  accountId: number;
  onAccountChange: (account: MappedAccount) => void;
}

/**
 * Dialog used to add/edit an Account's Brands.
 *
 * When using this Dialog you should load it on demand using `next/dynamic`,
 * this avoids this code bloating into page bundles and is loaded only
 * when required.
 */
const CustomBrandDialog: FC<CustomBrandDialogProps> = ({
  onClose,
  accountId,
  onAccountChange,
  existingDomains,
  ...customBrandFormProps
}) => {
  const { t } = useI18nStatic<'customBrandDialog'>(locales);
  const formApiRef = useRef<FormApi>(null);
  const [isLoading, setIsLoading] = useState(false);
  const isLargeScreen = useIsLargeScreen();
  const isEditing = !!customBrandFormProps.initialDomain;
  const { trackEvent } = useTracker();
  const appToast = useAppToast();

  return (
    <DialogBox
      fillViewport={!isLargeScreen}
      onClose={onClose}
      withPaddingX
      testId="customBrandDialog"
      // HACK: useCallback breaks the typing here
      renderHeader={useCallback<DialogBoxRenderHeader<typeof onClose>>(
        ({ close }) => {
          if (isLoading) return null;

          return (
            <DialogBoxHeader
              title={isEditing ? t('titleEdit') : t('titleAdd')}
              onCloseClick={() => close()}
              renderRight={({ textProps }) => (
                <Clickable
                  testId="submitCustomBrandForm"
                  onClick={() => formApiRef.current?.submit()}
                >
                  <Text {...textProps}>Save</Text>
                </Clickable>
              )}
            />
          );
        },
        [isLoading]
      )}
      renderContent={useCallback<DialogBoxRenderContent<typeof onClose>>(
        ({ close }) => {
          return (
            <Box padding="0 0 2.2rem 0">
              <CustomBrandForm
                {...customBrandFormProps}
                apiRef={formApiRef}
                existingDomains={existingDomains}
                onSubmit={async ({
                  brandName,
                  iconImage,
                  domain,
                  dynamicColoring,
                }) => {
                  const account = await putCustomBrandApi({
                    accountId,
                    urlPattern: domain,
                    icon: iconImage,
                    name: brandName,
                    dynamicColoring,
                  });

                  const isNew = !customBrandFormProps.initialDomain;

                  trackEvent({
                    type: 'change-custom-brands',
                    subType: isNew ? 'add' : 'update',
                    customBrandName: brandName,
                    customBrandUrlPattern: domain,
                    accountId,
                    customBrandImageUrl: iconImage,
                  });

                  onAccountChange(account);

                  appToast({
                    text: t('savedToast'),
                  });

                  await close();
                }}
                onDelete={async ({ domain }) => {
                  const account = await deleteCustomBrandApi({
                    accountId,
                    urlPattern: domain,
                  });

                  trackEvent({
                    type: 'change-custom-brands',
                    subType: 'remove',
                    accountId,
                    customBrandName: customBrandFormProps.initialBrandName!,
                    customBrandUrlPattern: customBrandFormProps.initialDomain!,
                    customBrandImageUrl: customBrandFormProps.initialIconImage!,
                  });

                  onAccountChange(account);

                  appToast({
                    text: t('deletedToast'),
                  });

                  await close();
                }}
                onChange={({ isLoading }) => {
                  setIsLoading(isLoading);
                }}
              />
            </Box>
          );
        },
        [accountId, existingDomains]
      )}
    />
  );
};

export default CustomBrandDialog;
