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

import type { PageTrackerContext } from '~/src/components/Page';
import type { SelectedTrack, StoredTrack } from '~/src/store/tracks/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 { 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 useSelectTrack from '~/src/hooks/useSelectTrack';
import { useI18n } from '~/src/lib/i18n';
import { selectStagedItemState } from '~/src/store/editStage/selectors';
import { useDispatch, useSelector } from '~/src/store/redux';
import { patchTrackConfig } from '~/src/store/tracks/actions/config';
import { stageTrackForEditAction } from '~/src/store/tracks/actions/edit';
import { createSelectTrack } from '~/src/store/tracks/selectors';
import useTrackItemContext from '../useTrackItemContext';

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

const SECTION_COMPONENTS = {
  ...CORE_EDIT_SECTIONS,
};

const EditTrackPage: FC<{
  trackId: number;
  stagedTrack: SelectedTrack;
  originalTrack: SelectedTrack;
}> = ({ trackId, stagedTrack, originalTrack: track }) => {
  const i18n = useI18n();
  const dispatch = useDispatch();

  const originalItemContext = useTrackItemContext({
    track,
    withAllLinks: true,
  });

  const itemContext = useTrackItemContext({
    track: stagedTrack,
    withAllLinks: true,
    originalItemContext,
  });

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

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

      await dispatch(
        patchTrackConfig({
          trackId,
          config,
          lastUpdatedAt: stagedTrack.updatedAtTimestamp,

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

            return true;
          },
        })
      );
    }, []),
  });

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

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

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

            ...baseItems,
          ];
        },
        [i18n]
      )}
      trackerContext={useMemo(
        (): PageTrackerContext => ({
          artistId: track.artistId,
          artistName: track.artistName,

          trackId: track.id,
          trackName: track.name,
        }),
        [track]
      )}
    />
  );
};

const useStagedTrack = (trackId: number) => {
  const selectStagedTrack = useMemo(() => {
    return createSelectTrack({
      selectStateItem: (state) => selectStagedItemState<StoredTrack>(state),
    });
  }, []);

  return useSelector((state: State) => selectStagedTrack(state, trackId));
};

const EditTrackPageContainer = ({ trackId }: { trackId: number }) => {
  const dispatch = useDispatch();
  const stagedTrack = useStagedTrack(trackId);
  const originalTrack = useSelectTrack(trackId);

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

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

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

  return (
    <EditTrackPage
      trackId={trackId}
      stagedTrack={stagedTrack}
      originalTrack={originalTrack}
    />
  );
};

export default EditTrackPageContainer;
