import { Alert, Button, Col, Row } from 'antd'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import DragDropContext from 'components/DragDropContext'
import PortalComponent from 'components/PortalComponent/PortalComponent'
import { Text } from 'components/Typography'
import { useModules } from 'hooks/useModules'
import reduce from 'lodash/reduce'
import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd'
import { useHistory } from 'react-router-dom'
import AffiliateCardModule from '../../../components/AffiliateCardModule'
import { Icon } from '../../../components/Icon'
import { Paragraph } from '../../../components/Typography'
import { useWindowSize } from '../../../hooks'
import {
  AffiliateItem,
  TalentProfileModule
} from '../../../models/talent/talent-profile-module.model'
import ModuleEditor from '../ModuleEditor'
import {
  AddAffiliateProduct,
  AddAffiliateProductResult,
  useToast
} from '@komi-app/creator-ui'
import {
  AffiliateModal,
  ProfileAmazonTags,
  appendAmazonTag
} from '../../../components/AffiliateModal'
import { uploadImageWithCrop } from '../../../utils/photo'
import { useIsOwner } from '../../../hooks/user-hooks'
import { useSelector } from 'react-redux'
import { selectUserData } from 'redux/User/selector'
import { FLAGS, getFeatureValue } from '@komi-app/flags-sdk'
import { useAnalyticsStartItemCreation } from 'hooks/useAnalyticsStartItemCreation'
import { useAnalyticsCompleteItemCreation } from 'hooks/useAnalyticsCompleteItemCreation'

interface ModuleAffiliateProps {
  module: TalentProfileModule<AffiliateItem>
  dragHandleProps?: DraggableProvidedDragHandleProps
  active: boolean
}

const ModuleAffiliate: React.FC<ModuleAffiliateProps> = ({
  module,
  dragHandleProps,
  active
}) => {
  const history = useHistory()
  const profileContext = useModules()

  const [modalVisible, setModalVisible] = useState(false)
  const [modalItem, setModalItem] = useState<AffiliateItem | undefined>(
    undefined
  )
  const [imageUploadError, setImageUploadError] = useState('')
  const [isUploading, setIsUploading] = useState(false)

  const isOwner = useIsOwner()
  const { createToast } = useToast()
  const user = useSelector(selectUserData)
  const profileId = user?.talentProfile?.id
  const amzTagsListJSON: ProfileAmazonTags = getFeatureValue(
    FLAGS.FEAT_SB_972_AFFILIATE_AMAZON_ASSOCIATE_TAG,
    {}
  )

  const { trackStartAddingItemToModule } = useAnalyticsStartItemCreation()
  const { trackCompleteAddingItemToModule } = useAnalyticsCompleteItemCreation()

  // useRef is needed to access the modal visible state during our async upload callback
  const modalVisibleRef = useRef(modalVisible)
  useEffect(() => {
    modalVisibleRef.current = modalVisible
  }, [modalVisible])

  const { width } = useWindowSize()
  const isMobileStyleChangesEnabled = width && width <= 768

  const itemList = useMemo(() => module.items, [module.items])

  const modalItemImage = modalItem?.image

  const modalItemWithImage = useMemo(() => {
    if (!modalItem) return undefined

    return {
      ...modalItem,
      url: modalItem.trackingUrl || modalItem.url,
      image: modalItemImage
    }
  }, [modalItem, modalItemImage])

  const onEditModuleCallback = useCallback(
    (moduleEdit: TalentProfileModule<AffiliateItem>) => {
      profileContext.setModule?.(moduleEdit)
      trackCompleteAddingItemToModule(moduleEdit)
    },
    [profileContext]
  )

  const onDropEnd = useCallback(
    (list: AffiliateItem[]) => {
      onEditModuleCallback({
        ...module,
        items: list.map((item, index) => ({ ...item, order: index })),
        isUpdate: true
      })
    },
    [module, onEditModuleCallback]
  )

  const onAddAffiliateItem = useCallback(
    async (newItem: AffiliateItem, result: AddAffiliateProductResult) => {
      onEditModuleCallback({
        ...module,
        items: [
          {
            ...newItem,
            title: result.title,
            visible: true
          },
          ...module.items
        ].map((item, index) => ({
          ...item,
          order: index
        })),
        isUpdate: true
      })

      setModalVisible(false)
      setModalItem(undefined)
      setIsUploading(false)
    },
    [module, onEditModuleCallback]
  )

  const onAddItemClicked = useCallback(() => {
    trackStartAddingItemToModule(module)
    setModalItem(undefined)
    setModalVisible(true)
  }, [])

  const onEditItemClicked = useCallback((affiliateItem: AffiliateItem) => {
    // Append the amazon associate tag to the affiliate product URL
    const amzTaggedURL = appendAmazonTag(
      profileId,
      affiliateItem.trackingUrl,
      amzTagsListJSON
    )

    setModalItem({
      ...affiliateItem,
      trackingUrl: amzTaggedURL ? amzTaggedURL : affiliateItem.trackingUrl
    })
    setModalVisible(true)
  }, [])

  const onCloseEditProductModal = useCallback(() => {
    setImageUploadError('')
    setModalVisible(false)
  }, [])

  const onEditAffiliateItem = useCallback(
    async (existingItem: AffiliateItem, result: AddAffiliateProductResult) => {
      let image = existingItem.image
      // We need to upload an image, don't save anything till we've uploaded it
      if (result.image && result.croppedAreaPixels) {
        setIsUploading(true)

        try {
          const uploadedImage = await uploadImageWithCrop(
            result.image,
            result.croppedAreaPixels
          )

          image = uploadedImage.url
        } catch (e) {
          setImageUploadError(e?.message || 'An unknown error occurred')
          setIsUploading(false)
          return
        }
      }

      // If the user closes the modal before we had a chance to save, don't save anything
      if (!modalVisibleRef.current) {
        setModalVisible(false)
        setModalItem(undefined)
        setImageUploadError('')
        setIsUploading(false)
        return
      }

      const items = module.items.map(item => {
        if (item.order === existingItem.order) {
          return {
            ...item,
            title: result.title,
            image
          }
        }
        return item
      })

      onEditModuleCallback({
        ...module,
        items,
        isUpdate: true
      })

      setModalVisible(false)
      setModalItem(undefined)
      setImageUploadError('')
      setIsUploading(false)
    },
    [module, onEditModuleCallback]
  )

  const onDeleteAffiliateItem = useCallback(
    (affiliateItem: AffiliateItem) => {
      const items = reduce(
        module.items,
        (results: any, item: any) => {
          if (item.order !== affiliateItem.order) {
            return [...results, { ...item, order: results.length }]
          }
          return results
        },
        []
      )

      onEditModuleCallback({
        ...module,
        items,
        isUpdate: true
      })
    },
    [module, profileContext.setModule]
  )

  const renderContent = () => {
    if (!itemList.length) {
      return (
        <React.Fragment>
          <Row justify="center">
            <Col span={24} className="text__align--center">
              <Icon name="empty-module" />
            </Col>
            <Col span={24} className="text__align--center max-w-393">
              <Paragraph preset="semibold18" className="d--block m__b--4">
                Nothing Here Yet
              </Paragraph>
              <Paragraph preset="regular14" className="d--block text--grey4">
                Click the button below to get started
              </Paragraph>
            </Col>
            <Col span={24} className="height--32 m__t--20">
              <Row justify="center">
                <Button
                  className="add-item-btn p--0"
                  type="link"
                  onClick={onAddItemClicked}
                >
                  <div className="d--flex justify__content--center align__items--center">
                    <Icon name="add-blue" />
                    <Text preset="semibold18" className="text--blue m__l--4">
                      Add New Item
                    </Text>
                  </div>
                </Button>
              </Row>
            </Col>
          </Row>
        </React.Fragment>
      )
    }

    function redirectToSettings(): void {
      if (isOwner) {
        history.push('/admin/settings/subscription')
      } else {
        createToast({
          text: 'You don’t have access to Billing & Payments settings, contact the owner of this Komi mini-site',
          semantic: 'warning',
          dismissible: true,
          durationMs: 5000
        })
      }
    }

    return (
      <React.Fragment>
        <Row
          align="middle"
          justify="space-between"
          className={isMobileStyleChangesEnabled ? 'm__b--8' : 'm__b--24'}
        >
          <Col className="height--32">
            <Button
              className="add-item-btn p--0"
              type="link"
              onClick={onAddItemClicked}
            >
              <div className="d--flex justify__content--center align__items--center">
                <Icon name="add-blue" />
                <Text preset="semibold18" className="text--blue m__l--4">
                  Add New Item
                </Text>
              </div>
            </Button>
          </Col>
          <Col>
            <Text preset="medium14" className="text--default opacity-6">
              {itemList.length}&nbsp;
              {itemList.length > 1 ? 'elements added' : 'element added'}
            </Text>
          </Col>
        </Row>
        <Row
          align="middle"
          justify="space-between"
          className={isMobileStyleChangesEnabled ? 'm__b--8' : 'm__b--24'}
        >
          <Alert
            className={'warning-alert fullwidth'}
            type="warning"
            icon={<Icon name="warning" />}
            description={
              <Paragraph prefixCls="regular16" className="leading-22">
                Link your PayPal account to earn affiliate revenue.{' '}
                <Text
                  onClick={redirectToSettings}
                  prefixCls="regular16"
                  className="leading-22 text--blue cursor-pointer"
                >
                  Go to Settings
                </Text>
              </Paragraph>
            }
            showIcon
            closeText={<Icon width={24} height={24} name="close-outline" />}
          />
        </Row>
        <DragDropContext
          droppableId="affiliate-child-drop"
          listClassName="product-list"
          itemIdPrefix="affiliate"
          direction="vertical"
          list={itemList}
          onDropEndCallback={onDropEnd}
        >
          {(dragProvided, snapshot, item, itemIndex) => {
            const isRender = active ? active : itemIndex < 2

            const key = itemIndex

            return isRender ? (
              <PortalComponent
                innerRef={dragProvided.innerRef}
                key={key}
                namespaceClass="product-list"
                provided={dragProvided}
                snapshot={snapshot}
                single={itemList?.length === 1}
              >
                <AffiliateCardModule
                  titleShortcut
                  index={itemIndex}
                  disableDrag={itemList?.length === 1}
                  item={item}
                  dragHandleProps={dragProvided.dragHandleProps || undefined}
                  module={module}
                  onEdit={onEditItemClicked}
                  onDelete={onDeleteAffiliateItem}
                />
              </PortalComponent>
            ) : (
              <></>
            )
          }}
        </DragDropContext>
        {!active && itemList.length > 2 && (
          <div className="d--flex justify__content--end align__items--center m__t--20 cursor-pointer">
            <Text preset="medium14" className="opacity-6">
              +{itemList.length - 2} More
            </Text>
          </div>
        )}
      </React.Fragment>
    )
  }

  return (
    <React.Fragment>
      <ModuleEditor module={module} dragHandleProps={dragHandleProps}>
        {modalVisible && modalItem && modalItemWithImage && (
          <AddAffiliateProduct
            product={modalItemWithImage}
            isEditing
            onClose={() => onCloseEditProductModal()}
            onDone={updated => onEditAffiliateItem(modalItem, updated)}
            errors={{ image: imageUploadError }}
            onPrevious={() => onCloseEditProductModal()}
            uploadingImage={isUploading}
            loading={isUploading}
          />
        )}
        {modalVisible && !modalItem && (
          <AffiliateModal
            visible
            onChangeVisible={() => setModalVisible(false)}
            onConfirmCallback={(newProduct, result) =>
              onAddAffiliateItem(newProduct, result)
            }
          />
        )}
        {renderContent()}
      </ModuleEditor>
    </React.Fragment>
  )
}

export function isIframeVideo(src: string): boolean {
  return src.endsWith('/iframe')
}

export default React.memo(ModuleAffiliate)
