import { memo, useCallback, useState } from 'react';
import Debug from 'debug';

import type { FC } from 'react';
import type { PageSectionComponent } from '../../types';
import type { VideosSectionItem, VideosSectionProps } from '../types';

import Box from '~/src/components/Box';
import Clickable from '~/src/components/Clickable';
import DialogBox from '~/src/components/DialogBox';
import { DialogBoxHeader } from '~/src/components/DialogBox/DialogBoxHeader';
import ErrorText from '~/src/components/ErrorText';
import Form from '~/src/components/Form';
import Gradient from '~/src/components/Gradient';
import YouTubeIcon from '~/src/components/Icon/YouTubeIcon';
import InputLabel from '~/src/components/InputLabel';
import { useEditActions } from '~/src/components/ItemPage/ItemPageEdit/useEditActions';
import {
  useAppAlert,
  useAppLoading,
} from '~/src/components/NextApp/lib/CoreUi';
import { SortableItem } from '~/src/components/Sortable';
import Text from '~/src/components/Text';
import TextInput from '~/src/components/TextInput';
import useHash from '~/src/hooks/useHash';
import { useI18n } from '~/src/lib/i18n';
import prettyWrap from '~/src/lib/utils/prettyWrap';
import { getYoutubeVideoApi } from '~/src/lib/youtube';
import { parseYoutubeVideoId } from '~/src/lib/youtube/utils';
import { usePageTheme } from '../../../hooks/theme';
import { EditWrapper } from '../../lib/EditWrapper';
import RemoveButton from '../../lib/RemoveButton';
import SectionTitle from '../../lib/SectionTitle';
import SortableHorizontalScroller from '../../lib/SortableHorizontalScroller';
import TextInputWithIconButton from '../../lib/TextInputWithIconButton';
import { MAX_VIDEOS_PER_SECTION } from '../constants';
import VideoListItem from '../VideoListItem';
import VideosSettings from './VideosSettings';

const debug = Debug('songwhip/VideosEdit');
const HASH_PARAM = 'videos';

const VideosSectionEdit: PageSectionComponent<VideosSectionProps> = ({
  title,
  items = [],
  sectionPath,
  autoplay,
}) => {
  const { hashParams, backToBeforeFirstHash, setHashParam } = useHash();
  const editItemHashParam = `${HASH_PARAM}:${sectionPath}:edit`;
  const editHashValue = hashParams[editItemHashParam];
  const editItemIndex = editHashValue ? Number(editHashValue) : undefined;
  const itemToEdit = editItemIndex !== undefined && items[editItemIndex];
  const { updateLayoutSection } = useEditActions();
  const { t } = useI18n();

  if (title === undefined) {
    title = t('item.defaultVideosTitle');
  }

  const onItemClick = useCallback(
    ({ data: { index } }) => {
      setHashParam({ [editItemHashParam]: index });
    },
    [editItemHashParam]
  );

  return (
    <div data-testid="videosEdit">
      <EditWrapper
        padding="1.6rem 1rem 2rem"
        sectionPath={sectionPath}
        renderSettingsContent={useCallback(
          ({ close }) => (
            <VideosSettings
              title={title}
              sectionPath={sectionPath}
              onSubmit={close}
              autoplay={autoplay}
            />
          ),
          [title, autoplay]
        )}
      >
        <VideosSectionEditContent
          title={title}
          items={items}
          onItemClick={onItemClick}
          sectionPath={sectionPath}
        />
      </EditWrapper>
      {itemToEdit && (
        <DialogBox
          testId="editVideoDialog"
          onClose={backToBeforeFirstHash}
          fillViewportOnSmallScreen
          renderContent={({ close, paddingX, paddingY }) => {
            return (
              <Form<{ title: string; link: string }>
                onSubmit={({ values }) => {
                  const itemsNext = [...items];

                  itemsNext[editItemIndex] = {
                    ...itemToEdit,
                    ...values,
                  };

                  updateLayoutSection({
                    sectionPath,

                    changedProps: {
                      items: itemsNext,
                    },
                  });

                  close();
                }}
              >
                <DialogBoxHeader
                  onCloseClick={close}
                  title={t('itemEdit.videos.edit.title')}
                  renderRight={({ textProps }) => (
                    <Clickable isSubmit testId="saveVideoChanges">
                      <Text {...textProps}>Save</Text>
                    </Clickable>
                  )}
                />
                <Box padding={`0 ${paddingX} ${paddingY}`}>
                  <InputLabel value="Video title">
                    <TextInput
                      defaultValue={itemToEdit.title}
                      placeholder="Enter video title"
                      required
                      name="title"
                      testId="titleInput"
                    />
                  </InputLabel>
                  {/* TODO: make image editable */}
                  {/* <InputLabel margin={`${paddingX} 0 0`} value="Video image">
                      <Image
                        src={itemToEdit.image}
                        borderRadius="0.4rem"
                        aspect={9 / 16}
                        style={{
                          opacity: 0.8,
                        }}
                      />
                    </InputLabel> */}
                  <RemoveButton
                    margin={`${paddingX} 0 0`}
                    text={t('itemEdit.videos.edit.remove')}
                    testId="removeVideo"
                    onClick={async () => {
                      const itemsNext = [...items];

                      itemsNext.splice(editItemIndex, 1);

                      await close();

                      updateLayoutSection({
                        sectionPath,

                        changedProps: {
                          items: itemsNext,
                        },
                      });
                    }}
                  />
                </Box>
              </Form>
            );
          }}
        />
      )}
    </div>
  );
};

const VideosSectionEditContent = memo<{
  items: VideosSectionProps['items'];
  title: VideosSectionProps['title'];
  sectionPath: string;
  onItemClick: (params: { data: { index: number } }) => void;
}>(({ items = [], title, sectionPath, onItemClick }) => {
  const { updateLayoutSection } = useEditActions();
  const totalItems = items.length;
  const hasMultiple = totalItems > 1;
  const isEmpty = totalItems === 0;
  const pageTheme = usePageTheme();
  const maxItemsReached = items.length >= MAX_VIDEOS_PER_SECTION;

  return (
    <>
      <SectionTitle text={title} minHeight="3.5rem" isSticky={false} />
      <SortableHorizontalScroller
        margin=".5rem -.8rem 0"
        gradientColor={pageTheme.backgroundColor}
        contentStyle={{
          padding: '0 1rem',
        }}
        renderContent={useCallback(
          ({ itemStyle }) => {
            if (isEmpty) {
              return (
                <Text isCentered size="1.4rem" padding="2rem 0">
                  Add some videos to this page
                </Text>
              );
            }

            return items.map(({ title, image, link }, index) => {
              return (
                <SortableItem
                  key={link}
                  className="videoItem"
                  style={{
                    ...itemStyle,
                    padding: '0 0.5rem',
                    width: hasMultiple ? '25rem' : '100%',
                  }}
                >
                  <VideoListItem
                    image={image}
                    link={link}
                    title={title}
                    fullWidth
                    withHref={false}
                    data={{ index }}
                    aspect={hasMultiple ? 9 / 13 : 9 / 16}
                    onClick={onItemClick as any}
                    imageOpacity={0.8}
                  >
                    <Gradient
                      coverParent
                      top="30%"
                      bottom="0"
                      zIndex={2}
                      to="rgba(0,0,0,0.7)"
                      flexColumn
                      padding="0.8rem 10%"
                      className="titleOverlay"
                      pointerEvents="none"
                    >
                      <Text
                        margin="auto 0 0"
                        size="1.1rem"
                        centered
                        lineClamp={1}
                        lineHeight="1.2em"
                        color="#fff"
                      >
                        {prettyWrap(title)}
                      </Text>
                    </Gradient>
                  </VideoListItem>
                </SortableItem>
              );
            });
          },
          [items]
        )}
        onDrop={useCallback(
          ({ removedIndex, addedIndex }) => {
            const itemsNext = [...items];
            const [removed] = itemsNext.splice(removedIndex, 1);

            itemsNext.splice(addedIndex, 0, removed);
            debug('order change', itemsNext);

            updateLayoutSection({
              sectionPath,

              changedProps: {
                items: itemsNext,
              },
            });
          },
          [items, updateLayoutSection]
        )}
      />
      <AddVideoButton
        sectionPath={sectionPath}
        items={items}
        isDisabled={maxItemsReached}
        onSubmit={({ item }) => {
          updateLayoutSection({
            sectionPath,

            changedProps: {
              items: [item, ...items],
            },
          });
        }}
      />
    </>
  );
});

export const toAddVideoDialogHashParam = (sectionPath: string) =>
  `${HASH_PARAM}:${sectionPath}:add`;

const AddVideoButton: FC<{
  sectionPath: string;
  items: VideosSectionItem[];
  onSubmit: (params: { item: VideosSectionItem }) => void;
  isDisabled?: boolean;
}> = ({ sectionPath, onSubmit, items, isDisabled }) => {
  const { backToBeforeFirstHash, setHashParam, hashParams } = useHash();
  const hashParam = toAddVideoDialogHashParam(sectionPath);
  const dialogOpen = hashParam in hashParams;
  const setAppLoading = useAppLoading();
  const appAlert = useAppAlert();
  const [isLoading, setIsLoading] = useState(false);
  const { t } = useI18n('itemEdit');

  const alreadyHasVideo = (videoId: string) =>
    items.some(({ link }) => {
      return parseYoutubeVideoId(link) === videoId;
    });

  return (
    <>
      <Clickable
        testId="addVideo"
        onClick={() => setHashParam({ [hashParam]: '' })}
        margin="2rem 0 0 0"
        isDisabled={isDisabled}
      >
        <Text size="1.7rem" isBold centered>
          {t('videos.addVideo')}
        </Text>
      </Clickable>
      {dialogOpen && (
        <DialogBox
          testId="addVideoDialog"
          onClose={() => backToBeforeFirstHash()}
          fillViewportOnSmallScreen
          renderContent={({ paddingX, paddingY, close }) => {
            return (
              <Form<{ link: string }>
                onSubmit={async ({ values }) => {
                  try {
                    debug('on submit', values);

                    setAppLoading(true);

                    const youtubeVideoId = parseYoutubeVideoId(values.link);

                    if (!youtubeVideoId) {
                      throw new Error(t('videos.errors.invalidLink'));
                    }

                    if (alreadyHasVideo(youtubeVideoId)) {
                      throw new Error(t('videos.errors.videoExists'));
                    }

                    setIsLoading(true);
                    const result = await getYoutubeVideoApi(youtubeVideoId);
                    debug('got youtube video', result);

                    const item: VideosSectionItem = {
                      title: result.title,
                      image: result.image,
                      link: result.link,
                      aspect: result.aspect,
                    };

                    await close();

                    onSubmit({
                      item,
                    });
                  } catch (error) {
                    appAlert({
                      title: 'Error',
                      content: <ErrorText error={error} />,
                    });
                  } finally {
                    setIsLoading(false);
                    setAppLoading(false);
                  }
                }}
              >
                <DialogBoxHeader
                  title={t('videos.addVideo')}
                  onCloseClick={close}
                  renderRight={({ textProps }) => (
                    <Clickable isSubmit testId="submit" isDisabled={isLoading}>
                      <Text {...textProps}>Add</Text>
                    </Clickable>
                  )}
                />
                <Box padding={`0 ${paddingX} ${paddingY}`}>
                  <TextInputWithIconButton
                    Icon={YouTubeIcon}
                    name="link"
                    autoFocus
                    isDisabled={isLoading}
                    toValidationMessage={({ value }) => {
                      const isYoutubeUrl = !!parseYoutubeVideoId(value);

                      if (!isYoutubeUrl) {
                        return t('videos.errors.invalidLink');
                      }
                    }}
                    placeholder={t('videos.linkInputPlaceholder')}
                    testId="linkInput"
                  />
                </Box>
              </Form>
            );
          }}
        />
      )}
    </>
  );
};

export default VideosSectionEdit;
