import type { MouseEvent } from 'react'
import {
  useCallback,
  useState,
  useEffect,
} from 'react'
import { useHistory } from 'react-router-dom'

import { useSetRecoilState } from 'recoil'

import type { PaymentIntent, StripeError } from '@stripe/stripe-js'

import last from 'lodash/last'
import isEmpty from 'lodash/isEmpty'
import size from 'lodash/size'

import { ProfileTypes } from 'config'

import {
  buyMatchSubscription,
  buyMatchPayOnceSubscription,
  notifySuccessfulSubscription,
  PaymentActions,
} from 'requests/buySubscription'
import type { OnFailedPaymentActionData } from 'requests/buySubscription'

import { dataForPayHighlights } from 'pages/HighlightsPage/storeHighlightsAtoms'

import { useCardsStore } from 'features/CardsStore'
import {
  Match,
  Steps,
  SubscriptionType,
} from 'features/BuyMatchPopup/types'
import { getProfileUrl } from 'features/ProfileLink/helpers'

import { isSubscribePopup } from 'helpers'

import { useSubscriptions } from './useSubscriptions'
import { useStripe3DSecure } from './useStripe3DSecure'

const requests = {
  [SubscriptionType.Month]: buyMatchSubscription,
  [SubscriptionType.Year]: buyMatchPayOnceSubscription,
  [SubscriptionType.PayPerView]: buyMatchPayOnceSubscription,
}

export const useBuyMatchPopup = () => {
  const history = useHistory()
  const { defaultCard, isHighlightsPage } = useCardsStore()
  const { handle3DSecure } = useStripe3DSecure()

  const [steps, setSteps] = useState<Array<Steps>>([])
  const [match, setMatch] = useState<Match | null>(null)
  const [error, setError] = useState('')
  const [loader, setLoader] = useState(false)
  const [disabledBuyBtn, setDisabledBuyBtn] = useState(false)
  const [showClearBtn, setShowClearBtn] = useState(false)
  const [lastSelectedPackage, setLastSelectedPackage] = useState('')
  const setDataHighlights = useSetRecoilState(dataForPayHighlights)

  const goTo = useCallback(
    (step: Steps, e?: MouseEvent<HTMLButtonElement>) => setSteps((state) => {
      e?.stopPropagation()
      setLoader(false)
      return [...state, step]
    }),
    [],
  )

  const goBack = useCallback((e?: MouseEvent<HTMLButtonElement>) => setSteps((state) => {
    e?.stopPropagation()
    const newState = [...state]
    newState.pop()
    return newState
  }), [])

  const {
    fetchSubscriptions,
    matchSubscriptions,
    onPackageSelect,
    onPeriodSelect,
    onSubscriptionSelect,
    resetSubscriptions,
    selectedPackage,
    selectedPeriod,
    selectedSubscription,
    setSelectedPackage,
    subscriptions,
  } = useSubscriptions()

  const onNext = (e: MouseEvent<HTMLButtonElement>) => goTo(Steps.SelectPackage, e)

  const openPopup = useCallback((matchData: Match) => {
    setMatch(matchData)
    setSteps([])
  }, [])

  useEffect(() => {
    if (isEmpty(matchSubscriptions)) return

    if (size(matchSubscriptions) === 1) {
      setSteps([Steps.SelectPackage])
      onSubscriptionSelect(matchSubscriptions[0])
    } else {
      setSteps([Steps.SelectSubscription])
    }
  }, [matchSubscriptions, onSubscriptionSelect])

  const closePopup = () => {
    setMatch(null)
    setSteps([])
    setError('')
    resetSubscriptions()
    setSelectedPackage(null)

    if (isSubscribePopup()) {
      history.replace({ search: '' })
    }
  }

  const redirectToMatchProfile = ({ id, sportType }: Match) => {
    const matchLink = getProfileUrl({
      id,
      profileType: ProfileTypes.MATCHES,
      sportType,
    })
    history.push(matchLink)
  }

  const onSuccessfulSubscription = () => goTo(Steps.Success)
  const postPaymentHandler = () => {
    if (!match) return
    if (!isSubscribePopup()) {
      redirectToMatchProfile(match)
    }
    closePopup()
  }

  const goToError = () => goTo(Steps.Error)

  const onConfirmationError = (stripeError?: StripeError) => {
    setError(stripeError?.message || '')
    goToError()
  }

  const onConfirmationSuccess = ({ id }: PaymentIntent) => {
    if (!selectedPackage) return
    const item = selectedPackage?.originalObject
    notifySuccessfulSubscription({ item, paymentIntentId: id })
      .then(onSuccessfulSubscription, goToError)
  }

  const onSuccessfulHighlights = () => {
    setDataHighlights((prev) => ({
      ...prev,
      isOpenThanksPopup: true,
    }))
  }

  const onConfirmationSuccessHiglights = ({ id }: PaymentIntent) => {
    notifySuccessfulSubscription({ paymentIntentId: id })
      .then(onSuccessfulHighlights)
  }

  const onUnsuccessfulSubscription = (data?: OnFailedPaymentActionData) => {
    switch (data?.action) {
      case isHighlightsPage && PaymentActions.ThreeDSecure:
        handle3DSecure(data.value)?.then(onConfirmationSuccessHiglights, onConfirmationError)
        break
      case PaymentActions.ThreeDSecure:
        handle3DSecure(data.value)?.then(onConfirmationSuccess, onConfirmationError)
        break
      case PaymentActions.Redirect:
        window.location.href = data.value
        break
      case undefined:
        onConfirmationError()
        break
    }
  }

  const subscribeToMatch = () => {
    if (!selectedPackage || !defaultCard) return

    const item = selectedPackage.originalObject
    const buy = requests[selectedPackage.type]
    setLoader(true)
    buy({ cardId: defaultCard.id, item }).then(
      onSuccessfulSubscription,
      onUnsuccessfulSubscription,
    )
  }

  const onBuyClick = (e?: MouseEvent<HTMLButtonElement>) => {
    e?.stopPropagation()
    if (defaultCard) {
      subscribeToMatch()
    } else {
      goTo(Steps.CardSelection, e)
    }
  }

  useEffect(() => {
    if (match) {
      fetchSubscriptions(match)
    }
  }, [match, fetchSubscriptions])

  return {
    close: closePopup,
    currentStep: last(steps),
    disabledBuyBtn,
    error,
    goBack,
    goTo,
    hasPreviousStep: size(steps) > 1,
    lastSelectedPackage,
    loader,
    match,
    matchSubscriptions,
    onBuyClick,
    onConfirmationSuccess,
    onConfirmationSuccessHiglights,
    onNext,
    onPackageSelect,
    onPeriodSelect,
    onSubscriptionSelect,
    onSuccessfulHighlights,
    onUnsuccessfulSubscription,
    open: openPopup,
    postPaymentHandler,
    selectedPackage,
    selectedPeriod,
    selectedSubscription,
    setDisabledBuyBtn,
    setLastSelectedPackage,
    setShowClearBtn,
    showClearBtn,
    subscriptions,
  }
}
