import { useCallback, useRef } from 'react';

import type { ComponentType } from 'react';
import type { PageSectionComponent } from '../../types';
import type { VideoMedia, VideoSectionProps } from '../types';
import type { VideoMediaViewProps } 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 { 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 { AddVideoButton } from './components/AddVideoButton';
import { EditVideoDialog } from './components/EditVideoDialog';
import { VideoView } from './components/VideoView';
import { toMediaDialogHashParam } from './utils';

const MEDIA_VIEW_COMPONENTS: Record<
  VideoMedia['type'],
  ComponentType<VideoMediaViewProps>
> = {
  video: VideoView,
};

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

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

  const editVideoDialogHashParam = toMediaDialogHashParam('edit', sectionPath);
  const editVideoDialogHashValue = getHashParam(editVideoDialogHashParam);
  const isEmptyItems = items.length === 0;

  const content = (
    <>
      <SortableHorizontalScroller
        testId="editVideoContent"
        scrollerRef={scrollerRef}
        margin="3.3rem 0 0"
        gradientColor={pageTheme.backgroundColor}
        forceOverflowing={items.length > 1}
        scrollerStyle={{ scrollSnapType: 'x mandatory' }}
        contentStyle={{ width: `${items.length * 100}%` }}
        renderContent={useCallback(
          ({ itemStyle }) =>
            items.map((item, index) => (
              <SortableItem
                key={item.storyId}
                tag="li"
                className="videoItem"
                style={{
                  ...itemStyle,
                  position: 'relative',
                  zIndex: 1,
                  width: `${100 / items.length}%`,
                  aspectRatio: '16 / 9',
                  padding: '0 1rem',
                  scrollSnapAlign: 'start',
                }}
              >
                {(() => {
                  const Component = MEDIA_VIEW_COMPONENTS[item.type];

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

            updateLayoutSection({
              sectionPath,

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

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

            return (
              <>
                {content}
                {activeEditItem && (
                  <EditVideoDialog
                    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">
          <AddVideoButton
            scrollerRef={scrollerRef}
            sectionPath={sectionPath}
            items={items}
          />
        </Box>
      </EditWrapper>
    </div>
  );
};
