import { notifier } from '@tidbcloud/uikit'
import { Card, Divider, Alert, Box, Flex, Typography, Popover, Button } from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { IconAlertCircle, IconLink03 } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { stringify } from 'qs'
import React, { useEffect } from 'react'
import { useHistory } from 'react-router-dom'

import { RBACRoles, RBACRoleUINames } from 'dbaas/contexts/access-control'
import { ORG_TYPE } from 'dbaas/features/Organization'
import { getCloudProviderLabel } from 'dbaas/features/Project'
import { MarketplacePayment } from 'dbaas/screens/OrgSettings/features/Billing/Marketplace'
import {
  CentralUserRole,
  useListLoginUserRoles,
  useOrgBindThirdParty,
  useValiadteThirdPartyToken
} from 'dbaas/services'
import { CentralUserProfileOrg } from 'dbaas/services/account/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { setLastCachedOrg } from 'dbaas/stores/localStorage'
import useStores from 'dbaas/stores/useStores'
import { useThirdParty } from 'dbaas/utils/marketplace'
import { eventTracking } from 'dbaas/utils/tracking'

const PopContent: React.FC<React.PropsWithChildren<{ content: React.ReactElement; target: React.ReactElement }>> = ({
  content,
  target
}) => {
  const [opened, { close, open }] = useDisclosure(false)

  return (
    <Popover withArrow opened={opened}>
      <Popover.Target>
        <span onMouseEnter={open} onMouseLeave={close}>
          {target}
        </span>
      </Popover.Target>
      <Popover.Dropdown>{content}</Popover.Dropdown>
    </Popover>
  )
}

const LinkButton: React.FC<
  React.PropsWithChildren<{
    disabled?: boolean
    linked?: boolean
    orgId: string
    accountProvider: string
    accountToken: string
    freeTrial: boolean
    vendor: string
  }>
> = ({ disabled, linked, orgId, accountProvider, accountToken, freeTrial, vendor }) => {
  const mutation = useOrgBindThirdParty()

  const handleBind = () => {
    if (disabled || linked || mutation.isLoading) {
      return
    }
    mutation.mutate(
      {
        orgId,
        data: {
          third_party_account_provider: accountProvider,
          third_party_account_token: accountToken,
          third_party_free_trial: freeTrial
        }
      },
      {
        onError(error) {
          notifier.error(getErrorMessage(error))
          eventTracking('Link Account Failed')
        },
        onSuccess() {
          notifier.success(`Linked with ${vendor} successfully!`, {
            onClose: () => {
              setLastCachedOrg(orgId)
              eventTracking('Link Account Success')
              window.location.href = '/org-settings/billing/payments'
            }
          })
        }
      }
    )
  }

  return (
    <Button
      loading={mutation.isLoading}
      data-mp-event="Link Account Button Clicked"
      disabled={disabled}
      onClick={handleBind}
      h={30}
      leftSection={<IconLink03 size={14} />}
    >
      {linked ? 'Linked' : 'Link'}
    </Button>
  )
}

export const LinkMarketplace: React.FC<React.PropsWithChildren<{}>> = observer(() => {
  const {
    store: { userProfile },
    actions: { setTopMenuState }
  } = useStores()
  const history = useHistory()

  const { accountProvider, accountToken, provider, freeTrial } = useThirdParty()

  const vendor = getCloudProviderLabel(provider)

  const mutation = useValiadteThirdPartyToken()

  const orgs = userProfile.orgs.filter((org) => org.org_type !== ORG_TYPE.ENTERPRISE)

  const { data: userRoles } = useListLoginUserRoles(
    { scope_types: ['ORG'] },
    {
      query: {
        refetchInterval: 60 * 1000
      },
      request: {
        paramsSerializer(params) {
          return stringify(params, { arrayFormat: 'repeat' })
        }
      }
    }
  )

  const userRolesMap: { [index: string]: CentralUserRole } = (userRoles?.items || []).reduce((prev, next) => {
    prev[next.scope_id] = next
    return prev
  }, {})

  useEffect(() => {
    mutation.mutate({
      data: {
        third_party_account_provider: accountProvider,
        third_party_account_token: accountToken
      }
    })
    // eslint-disable-next-line
  }, [])

  useEffect(() => {
    setTopMenuState(true)
    return () => {
      setTopMenuState(false)
    }
  }, [setTopMenuState])

  const codeUsed = mutation.data && mutation.data.third_party_account_code_already_binded

  const errMsg = mutation.isError
    ? getErrorMessage(mutation.error)
    : codeUsed
      ? `Your ${vendor} account is already linked to an organization.`
      : ''

  const columns: MRT_ColumnDef<CentralUserProfileOrg>[] = [
    {
      header: 'Organization Name',
      minSize: 200,
      accessorFn: (row) => {
        return (
          <a href={`/switch-org?orgId=${row.id}`} target="_blank" rel="noreferrer">
            {row.name || `Org (ID: ${row.id})`}
          </a>
        )
      }
    },
    {
      header: 'Role',
      size: 290,
      accessorFn: (row) => {
        const role = userRolesMap[row.id]?.role_name || ''
        return <div>{RBACRoleUINames[role] || ''}</div>
      }
    },
    {
      header: 'Action',
      size: 80,
      accessorFn: (row) => {
        const linked = !!row.third_party_account_code
        const role = userRolesMap[row.id]?.role_name || ''
        const roleName = RBACRoleUINames[role] || ''
        const permissionDeined = role !== RBACRoles.OrgOwner && role !== RBACRoles.OrgBillAdmin
        const tips = linked
          ? 'This organization is already linked.'
          : errMsg
            ? errMsg
            : permissionDeined
              ? `${roleName} doesn't have permission to link.`
              : ''
        const Ele = (
          <LinkButton
            disabled={linked || errMsg || permissionDeined}
            freeTrial={freeTrial}
            linked={linked}
            orgId={row.id}
            accountProvider={accountProvider}
            accountToken={accountToken}
            vendor={vendor}
          />
        )

        const showPopover = !linked && !errMsg && !permissionDeined

        return (
          <div>
            {showPopover ? (
              Ele
            ) : (
              <PopContent
                target={Ele}
                content={
                  <Typography fz={12} lh="18px" fw={500}>
                    {tips}
                  </Typography>
                }
              />
            )}
          </div>
        )
      }
    }
  ]

  const handleCancelLink = () => {
    setTopMenuState(false)
    history.replace('/clusters')
  }

  return (
    <Card sx={() => ({ width: 868, margin: '0 auto', marginTop: 24, marginBottom: 36 })} p={24}>
      <Flex align="flex-start" pb={24}>
        <Box sx={() => ({ flex: 1 })} className="title">
          <Typography fz={20} fw={700} lh="24px">
            Link to Your {vendor} Billing Account
          </Typography>
          <Typography variant="body-lg" mt={10}>
            You can select an existing organization to link with it.
          </Typography>
        </Box>
        <Button variant="default" data-mp-event="Cancel Link Account" onClick={handleCancelLink}>
          Cancel
        </Button>
      </Flex>
      <Card.Section>
        <Divider></Divider>
      </Card.Section>
      <Box pt={24}>
        {errMsg && (
          <Alert color="red" icon={<IconAlertCircle size={16} />}>
            <span>{errMsg}</span>
          </Alert>
        )}
        <MarketplacePayment shadow="none" withBorder={false} pl={0} pt={16} source={provider} />
      </Box>
      <Card.Section>
        <Divider></Divider>
      </Card.Section>
      <Box pt={24}>
        <Box h={32} lh="32px" mb={16}>
          <Typography fz={16} fw={700} display="inline-block">
            Select Existing Organizations
          </Typography>
          <Typography display="inline-block" ml={16}>
            {orgs.length} item{orgs.length > 1 ? 's' : ''}
          </Typography>
        </Box>
        <Alert color="yellow" icon={<IconAlertCircle size={16} />}>
          <span>
            The existing payment method for this organization will be replaced by your {vendor} billing account.
          </span>
        </Alert>
        <ProTable columns={columns} data={orgs} mantinePaperProps={{ mt: 16 }} />
      </Box>
    </Card>
  )
})

export default LinkMarketplace
