import { useCallback, useEffect, useRef } from 'react';
import { v4 as uuidv4 } from 'uuid';

import type { ComponentType } from 'react';
import type { PageSectionComponent } from '../../types';
import type { StoriesMedia, StoriesProps } from '../types';
import type { StoriesMediaViewProps } from './types';

import Box from '~/src/components/Box';
import { SortableItem } from '~/src/components/Sortable';
import Text from '~/src/components/Text';
import useHash from '~/src/hooks/useHash';
import useIsLargeScreen from '~/src/hooks/useIsLargeScreen';
import { useI18n } from '~/src/lib/i18n';
import { usePageTheme } from '../../../hooks/theme';
import { useEditActions } from '../../../ItemPageEdit/useEditActions';
import { EditWrapper } from '../../lib/EditWrapper';
import SortableHorizontalScroller from '../../lib/SortableHorizontalScroller';
import { AddMediaButton } from './components/AddMediaButton';
import { AudioView } from './components/AudioView';
import { EditMediaDialog } from './components/EditMediaDialog';
import { toMediaDialogHashParam } from './utils';

const MEDIA_VIEW_COMPONENTS: Record<
  StoriesMedia['type'],
  ComponentType<StoriesMediaViewProps>
> = {
  audio: AudioView,
};

export const StoriesSectionEdit: PageSectionComponent<StoriesProps> = ({
  sectionPath,
  items = [],
}) => {
  const scrollerRef = useRef<HTMLDivElement>(null);

  const { setHashParam, getHashParam, backToBeforeFirstHash } = useHash();
  const { updateLayoutSection } = useEditActions();
  const isLargeScreen = useIsLargeScreen();
  const { t } = useI18n('itemEdit');
  const pageTheme = usePageTheme();

  const editMediaDialogHashParam = toMediaDialogHashParam('edit', sectionPath);
  const editMediaDialogHashValue = getHashParam(editMediaDialogHashParam);
  const isMultipleItems = items.length > 1;
  const isEmptyItems = items.length === 0;

  // Generate storyIds for any items that don't have them when entering edit mode
  // This ensures storyIds are persisted even if the user just opens edit mode and saves
  useEffect(() => {
    const itemsNeedingStoryId = items.some((item) => !item.storyId);

    if (itemsNeedingStoryId) {
      const itemsWithStoryIds = items.map((item) =>
        item.storyId ? item : { ...item, storyId: uuidv4() }
      );

      updateLayoutSection({
        sectionPath,
        changedProps: {
          items: itemsWithStoryIds,
        },
      });
    }
  }, []); // Run once on mount

  const content = (
    <>
      <SortableHorizontalScroller
        testId="editStoriesContent"
        scrollerRef={scrollerRef}
        margin="3.3rem 0 0"
        gradientColor={pageTheme.backgroundColor}
        contentStyle={{ padding: '0 1rem' }}
        renderContent={useCallback(
          ({ itemStyle }) =>
            items.map((item, index) => (
              <SortableItem
                key={`${item.resourceId}-${index}`}
                tag="li"
                className="mediaItem"
                style={{
                  ...itemStyle,
                  position: 'relative',
                  zIndex: 1,
                  width: isLargeScreen ? '28rem' : '22rem',
                  height: isLargeScreen ? '48rem' : '38rem',
                  padding: '0 1rem',
                  margin: isMultipleItems ? 0 : '0 auto',
                }}
              >
                {(() => {
                  const Component = MEDIA_VIEW_COMPONENTS[item.type];

                  return (
                    <Component
                      {...item}
                      onClick={() => {
                        setHashParam({
                          [editMediaDialogHashParam]: `${index}`,
                        });
                      }}
                    />
                  );
                })()}
              </SortableItem>
            )),
          [items, isLargeScreen]
        )}
        onDrop={useCallback(
          ({ removedIndex, addedIndex }) => {
            const itemsNext = [...items];
            const [removed] = itemsNext.splice(removedIndex, 1);
            itemsNext.splice(addedIndex, 0, removed);

            updateLayoutSection({
              sectionPath,

              changedProps: {
                items: itemsNext,
              },
            });
          },
          [items]
        )}
      />
      <style jsx>{`
        :global(.mediaItem.smooth-dnd-ghost) {
          opacity: 0.8 !important;
          color: #fff !important;
        }
      `}</style>
    </>
  );

  return (
    <div data-testid="editStoriesSection">
      <EditWrapper padding="1.6rem 1rem 2rem" sectionPath={sectionPath}>
        {isEmptyItems ? (
          <Box
            testId="editStoriesEmptyContent"
            centerContent
            minHeight="22rem"
            margin="3.3rem 0 0"
          >
            <Text color="#555">{t('storiesSection.edit.empty')}</Text>
          </Box>
        ) : (
          (() => {
            const activeEditItemIndex = Number(editMediaDialogHashValue);
            const activeEditItem = items[activeEditItemIndex];

            return (
              <>
                {content}
                {activeEditItem && (
                  <EditMediaDialog
                    mediaType={activeEditItem.type}
                    media={activeEditItem}
                    onClose={backToBeforeFirstHash}
                    onSave={(itemNext) => {
                      const itemsNext = [...items];
                      itemsNext[activeEditItemIndex] = itemNext;

                      updateLayoutSection({
                        sectionPath,

                        changedProps: {
                          items: itemsNext,
                        },
                      });
                    }}
                    onRemove={async () => {
                      const itemsNext = [...items];
                      itemsNext.splice(activeEditItemIndex, 1);

                      updateLayoutSection({
                        sectionPath,

                        changedProps: {
                          items: itemsNext,
                        },
                      });
                    }}
                  />
                )}
              </>
            );
          })()
        )}
        <Box centerContent margin="1.6rem 0 0 0">
          <AddMediaButton
            scrollerRef={scrollerRef}
            sectionPath={sectionPath}
            items={items}
          />
        </Box>
      </EditWrapper>
    </div>
  );
};
