import { useCallback, useEffect, useMemo } from 'react';
import Debug from 'debug';

import type { PageTrackerContext } from '~/src/components/Page';
import type { SelectedAlbum, StoredAlbum } from '~/src/store/albums/types';
import type { State } from '~/src/store/types';
import type { FC } from 'react';

import { PageTypes } from '~/lib/types';
import ItemPageEdit from '~/src/components/ItemPage/ItemPageEdit';
import ItemPageEditHeader from '~/src/components/ItemPage/ItemPageEdit/components/ItemPageEditHeader';
import { CORE_EDIT_SECTIONS } from '~/src/components/ItemPage/ItemPageEdit/constants';
import useOnSave from '~/src/components/ItemPage/ItemPageEdit/useOnSave';
import {
  toBuyLinksFeatureItem,
  toStreamLinksFeatureItem,
} from '~/src/components/ItemPage/sections/ItemLinks/features';
import { toMerchFeatureItem } from '~/src/components/ItemPage/sections/MerchSection/features';
import { toPageTitleFeatureItem } from '~/src/components/ItemPage/sections/PageTitleSection';
import { toPresaveButtons2FeatureItem } from '~/src/components/ItemPage/sections/PresaveButtons2/features';
import { toShowsFeatureItem } from '~/src/components/ItemPage/sections/ShowsSection/features';
import { toVideosFeatureItem } from '~/src/components/ItemPage/sections/VideosSection/features';
import { PAGE_HEADER_HEIGHT } from '~/src/components/PageHeader';
import useSelectAlbum from '~/src/hooks/useSelectAlbum';
import { useI18n } from '~/src/lib/i18n';
import { createSelectAlbum } from '~/src/store/albums';
import { patchAlbumConfig } from '~/src/store/albums/actions/config';
import { stageAlbumForEditAction } from '~/src/store/albums/edit';
import { selectStagedItemState } from '~/src/store/editStage/selectors';
import { useDispatch, useSelector } from '~/src/store/redux';
import useAlbumItemContext from '../hooks/useAlbumItemContext';

const debug = Debug('songwhip/editAlbumPage');

const SECTION_COMPONENTS = {
  ...CORE_EDIT_SECTIONS,
};

const EditAlbumPage: FC<{
  albumId: number;
  stagedAlbum: SelectedAlbum;
  originalAlbum: SelectedAlbum;
}> = ({ albumId, stagedAlbum, originalAlbum: album }) => {
  const i18n = useI18n();
  const dispatch = useDispatch();

  const originalItemContext = useAlbumItemContext({
    album,
    withAllLinks: true,
  });

  const itemContext = useAlbumItemContext({
    album: stagedAlbum,
    withAllLinks: true,
    originalItemContext,
  });

  const { save } = useOnSave({
    itemContext,
    pagePath: stagedAlbum.pagePath,

    onSave: async (config) => {
      debug('on save', config);

      await dispatch(
        patchAlbumConfig({
          albumId,
          config,
          lastUpdatedAt: album.updatedAtTimestamp,

          showToastOnError: (error) => {
            if (error.code === 'ITEM_WRITE_CONFLICT') {
              return false;
            }

            return true;
          },
        })
      );

      // When the album is a draft override the toast success text to use
      // 'saved' instead of 'published'. Using "published" might cause panic
      // if the page is sensitive and the owner believes it's private.
      if (album.isDraft) {
        return i18n.t('item.events.changesSaved');
      }
    },
  });

  return (
    <ItemPageEdit
      pageType={PageTypes.EDIT}
      key={albumId}
      itemContext={itemContext}
      hasContent={!!album.name}
      testId="editAlbumPage"
      error={album.error}
      isLoading={!!album.isLoading}
      userCanEdit={!!album.userCanEdit}
      pagePath={album.pagePath}
      sectionComponents={SECTION_COMPONENTS}
      header={useMemo(() => {
        return {
          height: PAGE_HEADER_HEIGHT,
          content: (
            <ItemPageEditHeader
              pagePath={stagedAlbum.pagePath}
              saveChanges={save}
            />
          ),
        };
      }, [save])}
      getAddSectionItems={useCallback(
        ({ baseItems, itemContext }) => {
          return [
            // page specific sections
            toPresaveButtons2FeatureItem({ i18n, itemContext }),
            toStreamLinksFeatureItem({ i18n, itemContext }),
            toBuyLinksFeatureItem({ i18n, itemContext }),

            // main sections
            toPageTitleFeatureItem({ i18n, itemContext }),

            // other sections
            toVideosFeatureItem({ i18n, itemContext }),
            toMerchFeatureItem({ i18n, itemContext }),
            toShowsFeatureItem({ i18n, itemContext }),

            ...baseItems,
          ];
        },
        [itemContext, i18n]
      )}
      trackerContext={useMemo(
        (): PageTrackerContext => ({
          albumId: album.id,
          albumName: album.name,

          artistId: album.artistId,
          artistName: album.artistName,
        }),
        [album]
      )}
    />
  );
};

const useStagedAlbum = (albumId: number) => {
  const selectStagedAlbum = useMemo(() => {
    return createSelectAlbum({
      selectStateItem: (state) => selectStagedItemState<StoredAlbum>(state),
    });
  }, []);

  return useSelector((state: State) => selectStagedAlbum(state, albumId));
};

const EditAlbumPageContainer = ({ albumId }: { albumId: number }) => {
  const dispatch = useDispatch();
  const stagedAlbum = useStagedAlbum(albumId);
  const originalAlbum = useSelectAlbum(albumId);

  useEffect(() => {
    dispatch(stageAlbumForEditAction(albumId));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [albumId]);

  // TODO: Show an error message or redirect back to the album page
  if (!originalAlbum) return null;

  // TODO: The staged album would only be null on the first render,
  // but we should handle this case in the future
  if (!stagedAlbum) return null;

  return (
    <EditAlbumPage
      albumId={albumId}
      stagedAlbum={stagedAlbum}
      originalAlbum={originalAlbum}
    />
  );
};

export default EditAlbumPageContainer;
