import {
  Badge,
  Box,
  Button,
  Card,
  Flex,
  Group,
  Switch,
  SwitchProps,
  Tooltip,
  Typography,
  closeModal,
  openModal,
  notifier,
  Alert,
  ActionIcon
} from '@tidbcloud/uikit'
import { Form, MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconEdit03 } from '@tidbcloud/uikit/icons'
import { lowerCase, startCase } from 'lodash-es'
import { observer } from 'mobx-react'
import { useState } from 'react'

import config from 'config'
import { HeroComponent } from 'dbaas/components/Measurement'
import { AccessDeniedHoverHint, useAccessCheck } from 'dbaas/contexts/access-control'
import { AUTH_METHOD_TYPE, ENTERPRISE_SIGNIN_URL, ENTITY_STATUS, ORG_TYPE } from 'dbaas/features/Organization'
import { PageShell } from 'dbaas/layouts/v5/page'
import { useRequestSupport } from 'dbaas/screens/HelpCenter/RequestSupport/helper'
import { OrgPlanStatus } from 'dbaas/screens/Plans/constant'
import { PaymentMethodModal } from 'dbaas/screens/Stripe'
import {
  setAuthMethodStatus,
  updateAuthMethod,
  useListDomains,
  useShowAuthMethods,
  openOrgSso
} from 'dbaas/services/account'
import { CentralOrgAuthMethod } from 'dbaas/services/account/interface'
import { ConnectionType } from 'dbaas/services/auth'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import { Domains } from './Domains'
import { useEnableSSO } from './modal'
import { CopyURL, isMethodConfigured, normalizeAllowedEmailDomains, Settings, SettingsFormData } from './Setting'

interface MethodSwitchProps {
  name: string
  checked?: boolean
  onChange?: (value: boolean) => void
  disabled?: boolean
}

export const getMethodName = (method: CentralOrgAuthMethod) => {
  if (method.display_name) {
    return method.display_name
  }
  return startCase(lowerCase(ConnectionType[method.name || ''])) || method.name || ''
}

const MethodSwitch: React.FC<React.PropsWithChildren<MethodSwitchProps>> = ({ name, onChange, checked, disabled }) => {
  const handleChange: SwitchProps['onChange'] = (e) => {
    const value = e.currentTarget.checked
    onChange?.(value)
  }

  return (
    <Switch
      styles={() => ({
        root: {
          display: 'inline-block'
        }
      })}
      checked={checked}
      disabled={disabled}
      onChange={handleChange}
      label={
        <Typography variant="action-md" c="carbon.9">
          {name}
        </Typography>
      }
    />
  )
}

export const Authentication = observer(() => {
  const {
    store: { tenantData },
    actions: { refreshOrgData }
  } = useStores()

  const { data, refetch, isFetched } = useShowAuthMethods(tenantData.id, {
    query: {
      refetchOnWindowFocus: false
    }
  })
  const {
    data: domainsData,
    refetch: refetchDomains,
    isLoading: domainsLoading,
    isError: domainsError
  } = useListDomains(tenantData.id, {
    query: {
      refetchOnWindowFocus: false
    }
  })
  const domains = domainsData?.domains || []
  const enabled = tenantData.org_type === ORG_TYPE.ENTERPRISE

  const { open: enableSSO } = useEnableSSO()
  const { open: openSupport } = useRequestSupport()

  const [paymentModalVisible, setPaymentModalVisible] = useState(false)

  const [editingMethod, setEdittingMethod] = useState<CentralOrgAuthMethod | null>(null)

  const updateSettings = async (data: SettingsFormData) => {
    const type = ConnectionType[(data.name || '').toUpperCase()]
    const name = type ? type : data.type === AUTH_METHOD_TYPE.PASSWORD ? 'auth0' : data.name || ''
    const allowEmailDomains = normalizeAllowedEmailDomains(data.allow_email_domain_str)

    await updateAuthMethod(tenantData.id, {
      name,
      type: data.type || '',
      auto_provision: data.auto_provision,
      allow_email_domain: allowEmailDomains,
      oidc_config: data.oidc_config,
      saml_config: data.saml_config,
      scim_provision: data.scim_provision
    })
    // enable oidc after first set
    if (
      (data.type === AUTH_METHOD_TYPE.OIDC || data.type === AUTH_METHOD_TYPE.SAML) &&
      editingMethod &&
      !isMethodConfigured(editingMethod)
    ) {
      await setAuthMethodStatus(tenantData.id, {
        name,
        type: data.type || '',
        status: ENTITY_STATUS.ENABLE
      })
    }
    eventTracking(`${getMethodName(data)} Authentication Method Updated`)
    await refetch()
    notifier.success(`${getMethodName(data)} authentication method has been updated.`)
    setEdittingMethod(null)
  }

  const toggleModal = () => {
    setPaymentModalVisible((preState) => !preState)
  }

  const addCreditCard = () => {
    setPaymentModalVisible(true)
  }

  const handleCompleteAddCreditCard = () => {}

  const confirmDisabled = (method: CentralOrgAuthMethod) => {
    const modalId = 'confirm-turn-off-modal'
    const onSubmit = async () => {
      await setAuthMethodStatus(tenantData.id, {
        name: method.name || '',
        type: method.type || '',
        status: ENTITY_STATUS.DISABLE
      })
      await refetch()
      eventTracking('Confirm Turn Off Method', { name: method.name })
      closeModal(modalId)
    }
    eventTracking('Confirm Turn Off Method Modal Opened', { name: method.name })
    openModal({
      modalId,
      title: (
        <Typography variant="title-lg">Are you sure to disable {getMethodName(method)} authentication?</Typography>
      ),
      size: 480,
      centered: true,
      children: (
        <Form
          onSubmit={onSubmit}
          onCancel={() => {
            closeModal(modalId)
            eventTracking('Confirm Turn Off Method Modal Closed', { name: method.type })
          }}
          actionsProps={{ confirmProps: { color: 'red' } }}
        >
          <Typography variant="body-lg">
            This will prevent members in your organizations from logging in using {getMethodName(method)}
            {method.type === AUTH_METHOD_TYPE.PASSWORD ? '' : ' accounts'} until the method is reactivated.
          </Typography>
        </Form>
      )
    })
    return
  }

  const onlyOneMethodAvailable =
    data?.auth_methods?.filter((method) => method.status === ENTITY_STATUS.ENABLE).length === 1

  const disabledSwitch = !enabled || onlyOneMethodAvailable

  const actionAccessible = useAccessCheck('OrgAuthenticationAction')
  const columns: MRT_ColumnDef<CentralOrgAuthMethod>[] = [
    {
      header: 'Name',
      accessorFn: (row) => {
        const onChange = async (value: boolean) => {
          // OIDC/SAML need to config settings when enable if there is no config at the first time
          if (value && !isMethodConfigured(row)) {
            setEdittingMethod(row)
            return
          }
          // disabled need to confirm
          if (!value) {
            confirmDisabled(row)
            return
          }
          try {
            // enable method
            await setAuthMethodStatus(tenantData.id, {
              name: row.name || '',
              type: row.type || '',
              status: ENTITY_STATUS.ENABLE
            })
            notifier.success(`${getMethodName(row)} authentication method has been activated.`)
            eventTracking(`${getMethodName(row)} Authentication Method Activated`)
            await refetch()
          } catch (e) {
            notifier.error(getErrorMessage(e))
          }
        }
        return !disabledSwitch ? (
          <MethodSwitch
            checked={row.status === ENTITY_STATUS.ENABLE}
            onChange={onChange}
            name={getMethodName(row)}
            disabled={!actionAccessible}
          />
        ) : (
          <Flex align="center">
            <Tooltip
              label={
                onlyOneMethodAvailable && row.status === ENTITY_STATUS.ENABLE
                  ? 'At least one authentication method is required to keep enabled.'
                  : enabled
                    ? ''
                    : 'This method is currently disabled and cannot be activated until SSO is enabled.'
              }
              disabled={onlyOneMethodAvailable && row.status !== ENTITY_STATUS.ENABLE}
              multiline
              maw={264}
              withArrow
              position="top"
            >
              <span style={{ display: 'inline-block' }}>
                <MethodSwitch
                  disabled={
                    !actionAccessible || !enabled || (onlyOneMethodAvailable && row.status === ENTITY_STATUS.ENABLE)
                  }
                  name={''}
                  checked={row.status === ENTITY_STATUS.ENABLE}
                  onChange={onChange}
                />
              </span>
            </Tooltip>
            <Typography variant="action-md" c="carbon.9" sx={() => ({ alignSelf: 'flex-start' })}>
              {getMethodName(row)}
            </Typography>
          </Flex>
        )
      },
      mantineTableHeadCellProps: {
        sx: { width: '50% !important' }
      }
    },
    {
      header: 'Type',
      accessorFn: (row) => {
        return (
          <Typography my={11} variant="body-lg">
            {row.type}
          </Typography>
        )
      },
      mantineTableHeadCellProps: {
        sx: { width: '50% !important' }
      }
    },
    {
      header: enabled ? 'Action' : '',
      id: 'action',
      //right align the header and body cells
      mantineTableHeadCellProps: {
        align: 'center',
        sx: {
          width: '100px !important',
          maxWidth: '100px !important',
          minWidth: '100px !important'
        }
      },
      mantineTableBodyCellProps: {
        align: 'center',
        pl: 16,
        sx: {
          width: '100px !important',
          maxWidth: '100px !important',
          minWidth: '100px !important'
        }
      },
      accessorFn(row) {
        return row.type !== AUTH_METHOD_TYPE.PASSWORD && enabled ? (
          <ActionIcon
            variant="subtle"
            disabled={!actionAccessible}
            onClick={() => {
              eventTracking('Authentication Settigs Opened', { name: row.name })
              setEdittingMethod(row)
            }}
          >
            <IconEdit03 size={16} />
          </ActionIcon>
        ) : null
      }
    }
  ]

  const ssoOperationAllowed = tenantData.plan === OrgPlanStatus.ON_DEMAND

  return (
    <PageShell
      title="Authentication"
      headerProps={{
        sticky: true,
        bg: 'carbon.1'
      }}
      bodyProps={{ pt: 0 }}
    >
      <Card withBorder={true} shadow="none" p={24} mb={24}>
        {!enabled && !ssoOperationAllowed && (
          <Alert mb={24}>
            <Flex justify="space-between" align="center" py={2}>
              Organization SSO is a free feature for paid organization. Add a credit card to unlock it.
              <AccessDeniedHoverHint id="BillingPaymentCreation">
                {({ accessible }) => (
                  <Button size="xs" variant="outline" disabled={!accessible} px={8} onClick={addCreditCard}>
                    Add Credit Card
                  </Button>
                )}
              </AccessDeniedHoverHint>
            </Flex>
          </Alert>
        )}
        {config.ENTERPRISE_SSO_COOKIE_TIPS && (
          <Alert mb={24} color="yellow">
            If you plan to use SAML or OIDC, please <a onClick={() => openSupport()}>contact support</a> for guidance on{' '}
            <a href="https://developers.google.com/privacy-sandbox/3pcd" target="_blank" rel="noreferrer">
              managing upcoming changes to third-party cookies.
            </a>
          </Alert>
        )}
        <Group justify="space-between" wrap="nowrap" gap={32}>
          <div>
            <Flex align="center">
              <Typography variant="headline-sm">Cloud Organization SSO</Typography>
              {enabled ? (
                <Badge variant="dot" ml={8} c="peacock">
                  Enabled
                </Badge>
              ) : ssoOperationAllowed ? (
                <Badge variant="dot" ml={8} c="carbon">
                  Disabled
                </Badge>
              ) : (
                <Badge ml={8} radius={8} px={8} py={4} size="lg" styles={{ root: { textTransform: 'none' } }}>
                  Available for paid organization
                </Badge>
              )}
            </Flex>
            <Typography variant="body-lg" mt={8}>
              {enabled
                ? 'Cloud Organization SSO(Single Sign-On) is enabled for your organization. Organization members can log in from the custom URL.'
                : 'You do not have Cloud Organization SSO(Single Sign-On) configured for your organization. Members in your organization can only log in using the default public authentication methods. Enable Cloud Organization SSO to configure the organization-specific authentication methods.'}{' '}
              <a
                href="https://docs.pingcap.com/tidbcloud/tidb-cloud-org-sso-authentication"
                target="_blank"
                rel="noreferrer"
              >
                Learn more
              </a>
              .
            </Typography>
          </div>
          {!enabled && (
            <AccessDeniedHoverHint id="OrgAuthenticationAction">
              {({ accessible }) => (
                <Button
                  size="sm"
                  sx={() => ({ alignSelf: 'flex-start', flexShrink: 0 })}
                  disabled={!accessible || !ssoOperationAllowed}
                  onClick={() => {
                    enableSSO({
                      onSubmit: async (data) => {
                        await openOrgSso(tenantData.id, { company_name: data.company_name })
                        await refetch()
                        await refreshOrgData()
                        eventTracking('Enabled Cloud Organization SSO')
                        notifier.success('Cloud Organization SSO has been enabled successfully.')
                      },
                      orgId: tenantData.id
                    })
                  }}
                  data-mp-event="Enable Cloud Organization SSO Button Clicked"
                >
                  Enable
                </Button>
              )}
            </AccessDeniedHoverHint>
          )}
        </Group>
        <Box mt={24}>
          <Typography variant="title-lg" fz={16}>
            Custom URL
          </Typography>
          {!enabled ? (
            <>
              <Typography variant="body-lg">
                The URL where members in your organization will log in once Cloud Organization SSO is enabled.
              </Typography>
              <Box
                sx={(theme) => ({
                  backgroundColor: theme.colors.carbon[2],
                  marginTop: 16,
                  marginBottom: 16,
                  display: 'flex',
                  alignItems: 'center',
                  borderRadius: theme.defaultRadius,
                  border: `1px solid ${theme.colors.carbon[5]}`
                })}
              >
                <Typography
                  variant="label-lg"
                  c="carbon.7"
                  lh="40px"
                  sx={(theme) => ({ borderRight: `1px solid ${theme.colors.carbon[5]}`, padding: '0 12px' })}
                >
                  {ENTERPRISE_SIGNIN_URL}/
                </Typography>
                <Typography variant="label-lg" c="carbon.7" sx={() => ({ padding: '0 12px' })}>
                  your-company-name
                </Typography>
              </Box>
            </>
          ) : (
            <>
              <Typography variant="body-lg">The URL where your organization members will log in.</Typography>
              <CopyURL
                value={`${ENTERPRISE_SIGNIN_URL}/${tenantData.company_name || ''}`}
                mt={16}
                onClick={() => eventTracking('Copy Enterprise SSO URL')}
              />
            </>
          )}
        </Box>
        {/* <Divider orientation="horizontal" my={24} /> */}
        <Typography variant="title-lg" fz={16} mt={24} mb={16}>
          Authentication Methods
        </Typography>
        <ProTable
          columns={columns}
          mantineTableContainerProps={{
            sx: (theme) => ({
              'thead tr th': {
                paddingTop: 12,
                paddingBottom: 12,
                fontSize: 14,
                lineHeight: '20px',
                fontWeight: 500,
                color: theme.colors.carbon[9]
              }
            })
          }}
          data={data?.auth_methods || []}
        />
        <Domains
          orgId={tenantData.id}
          domains={domains}
          loading={domainsLoading}
          isError={domainsError}
          actionAccessible={actionAccessible}
          onRefresh={refetchDomains}
        />
        {isFetched && <HeroComponent />}
        {!enabled && !ssoOperationAllowed && (
          <PaymentMethodModal
            open={paymentModalVisible}
            onClose={toggleModal}
            onComplete={handleCompleteAddCreditCard}
          ></PaymentMethodModal>
        )}
      </Card>
      {!!editingMethod && (
        <Settings
          opened
          method={{
            ...editingMethod,
            name: getMethodName(editingMethod),
            allow_email_domain_str: editingMethod.allow_email_domain?.join(','),
            callback_url: data?.callback_url || '',
            saml_entity_id: data?.saml_entity_id || '',
            saml_post_back_url: data?.saml_post_back_url || '',
            scim_connector_base_url: data?.scim_connector_base_url,
            scim_supported_provisioning_actions: data?.scim_supported_provisioning_actions,
            scim_unique_identifier_field: data?.scim_unique_identifier_field
          }}
          domains={domains}
          onSubmit={updateSettings}
          onClose={() => {
            eventTracking('Authentication Settigs Closed', { name: editingMethod.name })
            setEdittingMethod(null)
          }}
        />
      )}
    </PageShell>
  )
})
