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

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

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

import { PAGES, ProfileTypes } from 'config'

import { isMatchPage } from 'helpers/isMatchPage'

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

import { useCardsStore } from 'features/CardsStore'
import {
  Match,
  Steps,
  SubscriptionType,
} from 'features/BuyMatchPopup/types'
import { getProfileUrl } from 'features/ProfileLink/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 } = 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 [selectedSubStep, setSelectedSubStep] = useState(false)
  const [selectedSubName, setSelectSubName] = useState<number>(0)

  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,
    fetchSubscriptionsPackages,
    initialSubscription,
    matchSubscriptions,
    onPeriodSelect,
    onSubscriptionPackagesSelect,
    onSubscriptionSelect,
    resetSubscriptions,
    selectedPeriod,
    selectedSubscription,
    selectedSubscriptionPackage,
    setSelectedSubscriptionPackage,
    subscriptions,
  } = useSubscriptions()

  const onChooseSub = () => {
    if (match) {
      fetchSubscriptionsPackages(match)
      setSelectedSubStep(true)
    }
  }

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

  useEffect(() => {
    if (!isEmpty(initialSubscription)) {
      !initialSubscription?.data || size(initialSubscription?.data) === 1
        ? setSteps([Steps.Subscriptions])
        : setSteps([Steps.SelectSubscription])
    }
  }, [subscriptions, initialSubscription])

  const closePopup = () => {
    setMatch(null)
    setSteps([])
    setError('')
    resetSubscriptions()
    setSelectedSubscriptionPackage(null)
    setSelectedSubStep(false)
    if (isMatchPage()) history.push(PAGES.home)
  }

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

  const onSuccessfulSubscription = () => goTo(Steps.Success)
  const postPaymentHandler = () => {
    closePopup()
    if (!match) return
    if (match.hasVideo || match.calc) {
      redirectToMatchProfile(match)
    } else {
      window.location.reload()
    }
  }

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

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

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

  const onUnsuccessfulSubscription = (data?: OnFailedPaymentActionData) => {
    switch (data?.action) {
      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 (!selectedSubscription || !defaultCard) return

    const item = selectedSubscription.originalObject
    const buy = requests[selectedSubscription.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)
    }
  }

  const getSub = useCallback(() => {
    if (match) {
      fetchSubscriptions(match)
    }
  }, [match, fetchSubscriptions])

  useEffect(() => {
    getSub()
  }, [getSub])

  return {
    close: closePopup,
    currentStep: last(steps),
    error,
    getSub,
    goBack,
    goTo,
    initialSubscription,
    loader,
    match,
    matchSubscriptions,
    onBuyClick,
    onChooseSub,
    onPeriodSelect,
    onSubscriptionPackagesSelect,
    onSubscriptionSelect,
    open: openPopup,
    postPaymentHandler,
    selectedPeriod,
    selectedSubName,
    selectedSubStep,
    selectedSubscription,
    selectedSubscriptionPackage,
    setSelectSubName,
    subscriptions,
  }
}
