import { PaymentMethodResult, SetupIntentResult } from '@stripe/stripe-js'
import {
  Card,
  Button,
  Box,
  Grid,
  Menu,
  Flex,
  CardProps,
  Typography,
  BackgroundImage,
  useMantineTheme,
  useComputedColorScheme
} from '@tidbcloud/uikit'
import { useHover } from '@tidbcloud/uikit/hooks'
import { IconDotsHorizontal } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import React, { useState } from 'react'

import { AccessDeniedHoverHint, useAccessCheck } from 'dbaas/contexts/access-control'
import {
  CentralPaymentMethodAuditLogReqOperation,
  FormsStripePaymentMethod,
  updatePaymentMethodAuditLog
} from 'dbaas/services'
import { useListPaymentMethods } from 'dbaas/services/billing'
import { FormsBillingConfig } from 'dbaas/services/billing/interface'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'
import cardBgDark from 'media/bg-creditcard.dark.svg'
import cardBgLight from 'media/bg-creditcard.light.svg'

import DeleteCardModal from '../DeleteCardModal'
import PaymentMethodModal from '../PaymentMethod/PaymentMethodModal'
import SetDefaultCardModal from '../SetDefaultCardModal'

export const findPaymentMethodById = (list: FormsStripePaymentMethod[], id: string) => {
  if (!list) return {}

  return list.find((item: FormsStripePaymentMethod) => item.id === id) || {}
}

const CreditCardItem: React.FC<
  React.PropsWithChildren<{
    info: FormsStripePaymentMethod
    active?: boolean
    disabled?: boolean
    onUpdate: (info: FormsStripePaymentMethod) => void
  }>
> = ({ info, active, onUpdate, disabled }) => {
  const { card, billing_details, id } = info
  const [isOpen, setIsOpen] = useState(false)
  const [isDeleteOpen, setDeleteOpen] = useState(false)
  const { hovered: mouseHovered, ref } = useHover()
  const isPaymentActionAccessible = useAccessCheck('BillingPaymentAction')

  const reportDeleteCard = (success: boolean) => {
    updatePaymentMethodAuditLog({
      operation: CentralPaymentMethodAuditLogReqOperation.DELETE,
      is_success: success,
      card_number_last4: card?.last4 || ''
    })
    eventTracking('Payment Card Item Delete Button Clicked')
  }

  const switchCardHandler = () => {
    setIsOpen(active ? false : true)
    eventTracking('Switch To This Card Button Clicked')
  }

  const theme = useMantineTheme()
  const colorScheme = useComputedColorScheme()

  const hovered = mouseHovered && !active

  const textColor = active || disabled ? 'white' : 'carbon.7'

  const Elem = (
    <Card
      sx={(theme) => ({
        backgroundColor: active || disabled ? 'transparent' : hovered ? theme.colors.carbon[4] : theme.colors.carbon[2],
        color: active || disabled ? theme.white : 'inherit',
        border: hovered && !active ? `1px solid ${theme.colors.carbon[4]}` : undefined,
        cursor: isPaymentActionAccessible ? 'pointer' : 'default',
        overflow: 'initial',
        height: 136,
        pointerEvents: disabled ? 'none' : undefined
      })}
      onClick={isPaymentActionAccessible ? switchCardHandler : undefined}
      ref={ref}
    >
      <Flex
        direction="column"
        justify="space-between"
        sx={() => ({
          height: '100%',
          '& > div': {
            display: 'flex',
            justifyContent: 'space-between'
          }
        })}
        ref={ref}
      >
        <div>
          <Typography variant="action-md" fw={500} c={active || disabled ? 'white' : 'carbon.8'}>
            {billing_details?.name}
          </Typography>
          <span>
            <Menu withinPortal>
              <Menu.Target>
                <IconDotsHorizontal
                  width={20}
                  height={20}
                  fill={active || disabled ? theme.white : theme.colors.carbon[8]}
                  onClick={(e: any) => {
                    eventTracking('Payment Card Item Ellipse Button Clicked')
                    e.stopPropagation()
                  }}
                />
              </Menu.Target>
              <Menu.Dropdown>
                <Menu.Item disabled={!isPaymentActionAccessible} onClick={() => onUpdate(info)}>
                  Update
                </Menu.Item>
                <Menu.Item
                  disabled={!isPaymentActionAccessible || !!active}
                  data-mp-eventName="Credit Card Delete Button Clicked"
                  onClick={(e) => {
                    e.stopPropagation()
                    setDeleteOpen(true)
                  }}
                >
                  Delete
                </Menu.Item>
              </Menu.Dropdown>
            </Menu>
          </span>
        </div>
        <Flex align="center" direction={hovered ? 'column' : 'row'}>
          <Typography variant="title-lg" c={active || disabled ? 'white' : undefined}>
            Credit card (ending in **{card?.last4?.slice(2)})
          </Typography>
        </Flex>
        <div>
          <Typography variant="action-sm" c={textColor} fw={400}>
            {card?.exp_month?.padStart(2, '0') || '-'}/{card?.exp_year || '-'}
          </Typography>
          {hovered && isPaymentActionAccessible ? (
            <Typography variant="title-md" c="peacock.7" lh="18px">
              Switch to this card
            </Typography>
          ) : (
            <Typography variant="action-sm" c={textColor}>
              {active ? 'Default' : ''}
            </Typography>
          )}
        </div>
      </Flex>
      <div onClick={(e) => e.stopPropagation()}>
        <SetDefaultCardModal
          id={id || ''}
          open={isOpen}
          onClose={() => {
            setIsOpen(false)
          }}
        ></SetDefaultCardModal>
      </div>
      <DeleteCardModal
        id={id || ''}
        opened={isDeleteOpen}
        onDelete={() => {
          reportDeleteCard(true)
          setDeleteOpen(false)
        }}
        onError={() => reportDeleteCard(false)}
        onClose={() => {
          setDeleteOpen(false)
        }}
      ></DeleteCardModal>
    </Card>
  )

  if (active) {
    return (
      <BackgroundImage
        src={colorScheme === 'dark' ? cardBgDark : cardBgLight}
        sx={(theme) => ({
          borderRadius: theme.defaultRadius,
          mixBlendMode: disabled ? 'luminosity' : undefined
        })}
      >
        {Elem}
      </BackgroundImage>
    )
  }

  return Elem
}

const CreditCardList: React.FC<
  React.PropsWithChildren<{
    defaultPaymentId: string
    cards: FormsStripePaymentMethod[]
    onUpdate: (info: FormsStripePaymentMethod) => void
    disabled?: boolean
  }>
> = ({ cards, onUpdate, defaultPaymentId, disabled }) => {
  const activeCard = findPaymentMethodById(cards, defaultPaymentId)

  return (
    <Grid gutter={24} mt={24}>
      {cards.map((card, index) => {
        return (
          <Grid.Col key={card.id} span={3} pt={index < 4 ? 0 : undefined}>
            <CreditCardItem info={card} active={card.id === activeCard.id} onUpdate={onUpdate} disabled={disabled} />
          </Grid.Col>
        )
      })}
    </Grid>
  )
}
export const reportPaymentMethodChange = (
  action: 'add' | 'edit' | null,
  success: boolean,
  paymentMethod: FormsStripePaymentMethod | undefined,
  methods: FormsStripePaymentMethod[],
  payload?: SetupIntentResult | PaymentMethodResult
) => {
  let paymentMethodId = ''
  if (payload && 'setupIntent' in payload && payload.setupIntent) {
    paymentMethodId = payload.setupIntent.payment_method?.toString() || ''
  }
  if (payload && 'paymentMethod' in payload && payload.paymentMethod) {
    paymentMethodId = payload.paymentMethod.id
  }

  updatePaymentMethodAuditLog(
    {
      operation:
        action === 'add'
          ? CentralPaymentMethodAuditLogReqOperation.ADD
          : CentralPaymentMethodAuditLogReqOperation.UPDATE,
      is_success: success,
      card_number_last4: paymentMethod
        ? paymentMethod.card?.last4 || ''
        : payload
          ? findPaymentMethodById(methods, paymentMethodId).card?.last4 || ''
          : ''
    },
    { isHandleErr: true }
  ).catch((_e) => {})
}

interface CreditCardProps extends Omit<CardProps, 'children'> {
  disabled?: boolean
  billingConfig?: FormsBillingConfig
}

export default observer((props: CreditCardProps) => {
  const [paymentMethod, setPaymentMethod] = useState<FormsStripePaymentMethod | undefined>(undefined)
  const {
    actions,
    store: { payments, tenantData }
  } = useStores()

  const { paymentMethods: currentPayments, defaultPaymentId } = payments

  const { billingConfig } = props

  const { data: prevPayments } = useListPaymentMethods(tenantData.id, billingConfig?.billing_config_id!, {
    query: {
      enabled: !!billingConfig?.billing_config_id
    }
  })

  const togglePaymentModal = () => {
    setAction(null)
    setPaymentMethod(undefined)
  }
  const [action, setAction] = useState<'edit' | 'add' | null>(null)

  const addCreditCard = () => {
    setPaymentMethod(undefined)
    setAction('add')
  }

  const onComplete = async (payload?: SetupIntentResult | PaymentMethodResult) => {
    // sync all data
    actions.fetchPaymentMethods(tenantData.id)
    actions.fetchBillingProfile(tenantData.id)
    actions.fetchOrgBillingInfo()
    actions.fetchTenantPlanInfo()
    const data = await actions.fetchPaymentMethods(tenantData.id)
    reportPaymentMethodChange(action, true, paymentMethod, data, payload)
  }

  const paymentMethods = !!billingConfig ? prevPayments || [] : currentPayments

  return (
    <Card p={24} pb={32} {...props}>
      <Flex justify="space-between">
        <Typography variant="headline-sm" fz={18} c="carbon.8">
          Credit Cards
        </Typography>
        {action === null && !!paymentMethods.length && (
          <AccessDeniedHoverHint id="BillingPaymentCreation" reason={{ hoverCardProps: { position: 'top' } }}>
            {({ accessible }) => (
              <Button
                size="sm"
                disabled={!accessible || props.disabled}
                data-mp-event="Payment Add A New Card Button Clicked"
                onClick={addCreditCard}
              >
                Add a New Credit Card
              </Button>
            )}
          </AccessDeniedHoverHint>
        )}
      </Flex>
      {action === null && !!paymentMethods.length && (
        <CreditCardList
          disabled={props.disabled}
          cards={paymentMethods}
          defaultPaymentId={defaultPaymentId}
          onUpdate={(data) => {
            setAction('edit')
            setPaymentMethod(data)
          }}
        />
      )}
      {action === null && !paymentMethods.length && (
        <AccessDeniedHoverHint id="BillingPaymentCreation">
          {({ accessible }) => (
            <Box
              sx={(theme) => ({
                textAlign: 'center',
                marginTop: 24,
                backgroundColor: theme.colors.carbon[3],
                height: 136,
                borderRadius: theme.defaultRadius,
                cursor: 'pointer',
                pointerEvents: !accessible || props.disabled ? 'none' : undefined
              })}
              onClick={() => {
                if (!accessible || props.disabled) {
                  return
                }
                setAction('add')
                eventTracking('Payment Add A New Card Button Clicked')
              }}
            >
              <Typography title="action-lg" c="peacock.7" lh="136px">
                Add a New Card
              </Typography>
            </Box>
          )}
        </AccessDeniedHoverHint>
      )}
      {action !== null && (
        <PaymentMethodModal
          open={true}
          onClose={togglePaymentModal}
          onComplete={onComplete}
          paymentMethod={paymentMethod}
        />
      )}
    </Card>
  )
})
