import { Button } from 'antd'
import React, { useCallback, useEffect, useState } from 'react'
import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd'

import ModuleEditor from '../ModuleEditor'
import EmptyModule from './EmptyModule'

import { useDispatch } from 'react-redux'
import { updateSpotifyUserActions } from 'redux/User/actions'
import { selectLocalizationSelected, selectUserData } from 'redux/User/selector'
import { SpotifyUser } from 'redux/User/types'
import { useTypedSelector } from 'redux/rootReducer'

import DragDropContext from 'components/DragDropContext'
import { Icon } from 'components/Icon'
import MediaCardModule from 'components/MediaCardModule'
import PopupWindow from 'components/PopupWindowSpotifyAuth'
import PortalComponent from 'components/PortalComponent/PortalComponent'
import {
  PreReleaseCustomModal,
  PreReleaseSmartModal
} from 'components/PreReleaseModal'
import SelectContentTypeModal from 'components/SelectContentTypeModal'
import { SelectContentItem } from 'components/SelectContentTypeModal/SelectContentTypeModal'
import { Text } from 'components/Typography'

import {
  MusicItem,
  TalentProfileModule
} from 'models/talent/talent-profile-module.model'

import copyToClipboard from 'copy-to-clipboard'
import Cookies from 'js-cookie'
import { ArrayServices } from 'utils/array'
import notification from 'utils/notification'
import { convertToUrl, profileUrl } from 'utils/url'

import { userService } from 'services'
import {
  KOMI_SPOTIFY_ACCESS_TOKEN,
  KOMI_SPOTIFY_REFRESH_TOKEN
} from 'services/SpotifyService'

import { useAnalytics } from 'hooks/useAnalytics'
import { useModules } from 'hooks/useModules'

import { FLAGS, useFeatureIsOn } from '@komi-app/flags-sdk'
import { SmartLinkModal } from 'components/SmartLinkGenerator/SmartLinkModal'
import { SEGMENT_EVENTS } from 'constants/segment'
import { isEmptyModule } from 'utils/modules'
import { MusicReleaseType, MusicReleaseMode } from '@komi-app/shared-types'
import { useCreatorTracking, CreatorEvent } from '@komi-app/analytics-sdk'
import { trackingProps } from 'utils/tracking'
import { useAnalyticsStartItemCreation } from 'hooks/useAnalyticsStartItemCreation'
import { useAnalyticsCompleteItemCreation } from 'hooks/useAnalyticsCompleteItemCreation'

const MusicCardMemo = React.memo(MediaCardModule)

export const musicContentTypes: SelectContentItem[] = [
  {
    name: MusicReleaseType.NORMAL,
    title: 'Smart Links',
    description:
      'Share smart links to released tracks that drive your fans to multiple platforms, maximising streams and fan engagement',
    icon: <Icon name="smart-link" />
  },
  {
    name: MusicReleaseType.PRE_SAVE,
    title: 'Pre-Release Smart Link',
    description:
      'Start a pre-release campaign allowing fans to save your tracks or albums to their library before their release, maximising release day streams',
    icon: <Icon name="pre-release" />
  },
  {
    name: MusicReleaseType.CUSTOM_PRE_SAVE,
    title: 'Pre-Release Custom Link',
    description:
      'Use your custom pre-release landing page to redirect fans to multiple streaming platforms',
    icon: <Icon name="pre-release-custom" />
  }
]

interface ModuleMusicProps {
  module: TalentProfileModule<MusicItem>
  dragHandleProps?: DraggableProvidedDragHandleProps
  active: boolean
}
interface MusicEditState {
  isEdit: boolean
  music?: MusicItem
  musicEditIndex?: number
}

const ModuleMusic: React.FC<ModuleMusicProps> = ({
  module,
  dragHandleProps,
  active
}) => {
  const dispatch = useDispatch()

  const { sendSegmentEvent } = useAnalytics()

  const [showContentModal, setShowContentModal] = useState(false)
  const [musicList, setMusicList] = useState<MusicItem[]>([])
  const [selectedContentType, setSelectedContentType] =
    useState<MusicReleaseType>()
  const [musicEditState, setMusicEditState] = useState<MusicEditState>({
    isEdit: false
  })

  // const profileContext = useContext(ProfileContext);
  const profileContext = useModules()

  const user = useTypedSelector(selectUserData)
  const localizationSelected = useTypedSelector(selectLocalizationSelected)

  const hasSpotifyPopupFix = useFeatureIsOn(FLAGS.FIX_SB_286_SPOTIFY_POPUP)
  const useAnalyticsSDK = useFeatureIsOn(FLAGS.USE_ANALYTICS_SDK_TALENT)
  const { createTracker } = useCreatorTracking()
  const elementCreate = createTracker(CreatorEvent.ELEMENT_CREATED)
  const { trackStartAddingItemToModule } = useAnalyticsStartItemCreation()
  const { trackCompleteAddingItemToModule } = useAnalyticsCompleteItemCreation()

  useEffect(() => {
    setMusicList(
      module.items.map((music, index) => ({
        ...music,
        order: index
      }))
    )
    return () => {}
  }, [module.items, module.visible])

  // TODO: Move these outside of the module. They're not dependent on
  // anything within the module
  const handleRefreshToken = async (callback: any) => {
    try {
      const result = await userService.spotifyRefreshToken()
      if (result && 'ok' in result) {
        dispatch(
          updateSpotifyUserActions.REQUEST({
            ...result.response,
            callback: callback
          })
        )
      } else {
        throw new Error("Cann't refresh token spotify.")
      }
    } catch (ex: any) {
      await handleSpotifySignIn(callback)
      return
    }
  }
  const handleSpotifySignIn = async (callback: any) => {
    if (hasSpotifyPopupFix) {
      const popup = PopupWindow.open('spotify-authorization', 'about:blank', {
        height: 1000,
        width: 600
      })

      const result = await userService.spotifyConnect({
        callbackUrl: window.location.href
      })

      if (!!result && 'ok' in result) {
        popup.navigate(result.response.url)

        popup.then(
          (data: SpotifyUser) => {
            dispatch(
              updateSpotifyUserActions.REQUEST({
                ...data,
                callback: callback
              })
            )
          },
          (error: any) => {
            console.error(error)
          }
        )
      }
    } else {
      const result = await userService.spotifyConnect({
        callbackUrl: window.location.href
      })

      if (!!result && 'ok' in result) {
        const popup = PopupWindow.open(
          'spotify-authorization',
          result.response.url,
          {
            height: 1000,
            width: 600
          }
        )

        popup.then(
          (data: SpotifyUser) => {
            dispatch(
              updateSpotifyUserActions.REQUEST({
                ...data,
                callback: callback
              })
            )
          },
          (error: any) => {
            console.error(error)
          }
        )
      }
    }
  }
  const handleConnectSpotify = async (callback: any) => {
    if (
      user?.spotifyRefreshToken ||
      user?.thirdPartyInfo?.spotifyRefreshToken ||
      Cookies.get(KOMI_SPOTIFY_REFRESH_TOKEN)
    ) {
      await handleRefreshToken(callback)
    } else {
      await handleSpotifySignIn(callback)
    }
  }

  const handleSubmitType = useCallback(
    (type: MusicReleaseType) => {
      setShowContentModal(false)
      setSelectedContentType(type)
    },
    [module]
  )

  const onBeforeAddProduct = useCallback(async () => {
    if (!Cookies.get(KOMI_SPOTIFY_ACCESS_TOKEN)) {
      await handleConnectSpotify(() => onAddMusic())
      return
    }
    onAddMusic()
  }, [selectedContentType])

  const onBeforeEditProduct = useCallback(async (music: MusicItem) => {
    //the new pre-save flow requires connecting the spotify api along with the other music modules
    if (!Cookies.get(KOMI_SPOTIFY_ACCESS_TOKEN)) {
      await handleConnectSpotify(() => onEditMusic(music))
      return
    }
    onEditMusic(music)
  }, [])

  const onAddMusic = useCallback(() => {
    trackStartAddingItemToModule(module)
    setMusicEditState(preState => ({
      ...preState,
      isEdit: false,
      music: undefined,
      musicIndex: undefined
    }))
    // setVisible(true);
    setSelectedContentType(undefined)
    setShowContentModal(true)
  }, [])
  const onEditMusic = useCallback((music: MusicItem) => {
    setMusicEditState(preState => ({
      ...preState,
      isEdit: true,
      music: music,
      musicIndex: music.order
    }))
    setSelectedContentType(music.type || MusicReleaseType.NORMAL)
  }, [])
  const onDeleteMusic = useCallback(
    (music: MusicItem) => {
      profileContext.setModule({
        ...module,
        items: ArrayServices.removeWithIndex(
          module.items,
          music.order as number
        ),
        isUpdate: true
      })
    },
    [module, profileContext.setModule]
  )

  const onCopySmartLink = useCallback(
    (music: MusicItem) => {
      // user?.username coming up null in some cases, therefore parsing the name from the url using utl function 'profileUrl'
      // const komiLink = createKomiDomain(user?.username || "");

      const linkTail = music.urlSlug || convertToUrl(music.metadata?.name)
      const link = `${profileUrl}/music/${linkTail}`

      copyToClipboard(link)
      notification.success({
        message: 'The smart link has been copied to clipboard'
      })
    },
    [user]
  )

  const onDropEndMusics = useCallback(
    (list: MusicItem[]) => {
      profileContext.setModule({
        ...module,
        items: list.map((item, index) => ({ ...item, order: index })),
        isUpdate: true
      })
    },
    [module, profileContext.setModule]
  )

  const onSaveProductCallback = useCallback(
    (music: MusicItem) => {
      const moduleItems = musicEditState.isEdit
        ? ArrayServices.updateWithIndex(
            module.items,
            music.order as number,
            music
          )
        : ArrayServices.unshift(module.items, music)

      const moduleEdit = {
        ...module,
        items: moduleItems,
        isUpdate: true
      }

      profileContext.setModule(moduleEdit)
      trackCompleteAddingItemToModule(moduleEdit)

      if (!musicEditState.isEdit) {
        let type = 'SMART LINK'
        if (music.releaseDate) {
          type =
            music.releaseType === MusicReleaseMode.CUSTOM
              ? 'CUSTOM PRE-SAVE'
              : 'KOMI PRE-SAVE'
        }

        const { pageId, pageName } = trackingProps(type, localizationSelected)

        useAnalyticsSDK
          ? elementCreate({ pageId, pageName, type })
          : sendSegmentEvent(SEGMENT_EVENTS.ELEMENT_CREATED, {
              'Module Type': type,
              'Page ID': localizationSelected?.id || null,
              'Page Name': localizationSelected?.name || 'Default'
            })
      }
    },
    [
      module,
      musicEditState,
      localizationSelected,
      profileContext.setModule,
      sendSegmentEvent
    ]
  )

  const handleSetVisible = () => {
    setSelectedContentType(undefined)
    setMusicEditState(preState => ({
      ...preState,
      isEdit: false,
      music: undefined,
      musicIndex: undefined
    }))
  }

  const reduceContentTypeToModal = useCallback(
    (contentType?: MusicReleaseType) => {
      switch (contentType) {
        case MusicReleaseType.NORMAL:
          return (
            <SmartLinkModal
              onFinish={onSaveProductCallback}
              onCancel={handleSetVisible}
              isEdit={musicEditState.isEdit}
              music={musicEditState.music}
            />
          )

        case MusicReleaseType.PRE_SAVE:
          return (
            <PreReleaseSmartModal
              isEdit={musicEditState.isEdit}
              music={musicEditState.music}
              onFinish={onSaveProductCallback}
              onCancel={handleSetVisible}
            />
          )

        case MusicReleaseType.CUSTOM_PRE_SAVE:
          return (
            <PreReleaseCustomModal
              isEdit={musicEditState.isEdit}
              music={musicEditState.music}
              onFinish={onSaveProductCallback}
              onCancel={handleSetVisible}
            />
          )

        default:
          throw new Error(`Unhandled music item type '${contentType}'`)
      }
    },
    [musicEditState]
  )

  return (
    <React.Fragment>
      <ModuleEditor module={module} dragHandleProps={dragHandleProps}>
        {isEmptyModule(module) ? (
          <React.Fragment>
            <EmptyModule
              titleAction="Add New Track"
              onClick={onBeforeAddProduct}
            />
          </React.Fragment>
        ) : (
          <React.Fragment>
            <div className="d--flex justify__content--between align__items--center m__b--22">
              <Button
                data-testid="module-music--add-track"
                className="add-item-btn p--0"
                type="link"
                onClick={onBeforeAddProduct}
              >
                <div className="d--flex justify__content--center align__items--center p__r--8">
                  <Icon name="add-blue" />
                  <Text preset="semibold18" className="text--blue m__l--4">
                    Add New Track
                  </Text>
                </div>
              </Button>
              <Text
                data-testid="module-music--track-count"
                preset="medium14"
                className="text--default opacity-6"
              >
                {musicList.length} tracks added
              </Text>
            </div>

            <DragDropContext
              droppableId="product-child-drop"
              listClassName="product-list"
              itemIdPrefix="product"
              direction="vertical"
              list={active ? musicList : musicList.slice(0, 2)}
              onDropEndCallback={onDropEndMusics}
            >
              {(dragProvided, snapshot, item, productIndex) => {
                const isRender = active ? active : productIndex < 2
                return isRender ? (
                  <PortalComponent
                    innerRef={dragProvided.innerRef}
                    key={productIndex}
                    namespaceClass="product-list"
                    provided={dragProvided}
                    snapshot={snapshot}
                    single={musicList?.length === 1}
                  >
                    <MediaCardModule
                      titleShortcut
                      disableDragDrop={module.items.length <= 1}
                      index={productIndex}
                      disableDrag={musicList?.length === 1}
                      item={item}
                      onEdit={onBeforeEditProduct}
                      onDelete={onDeleteMusic}
                      dragHandleProps={dragProvided.dragHandleProps}
                      onCopySmartLink={onCopySmartLink}
                      module={module}
                    />
                  </PortalComponent>
                ) : (
                  <></>
                )
              }}
            </DragDropContext>
            {!active && musicList.length > 2 && (
              <div className="d--flex justify__content--end align__items--center m__t--20 cursor-pointer">
                <Text preset="medium14" className="opacity-6">
                  +{musicList.length - 2} More
                </Text>
              </div>
            )}
          </React.Fragment>
        )}
      </ModuleEditor>

      {selectedContentType && reduceContentTypeToModal(selectedContentType)}

      <SelectContentTypeModal
        types={musicContentTypes}
        defaultValue={MusicReleaseType.NORMAL}
        show={showContentModal}
        toggleModal={setShowContentModal}
        handleSubmit={handleSubmitType}
      />
    </React.Fragment>
  )
}

export default ModuleMusic
