import { Accordion, Drawer, Typography } from '@tidbcloud/uikit'
import { FormSwitch, FormTextInput, Form, FormPasswordInput, FormTextareaInput } from '@tidbcloud/uikit/biz'
import React from 'react'
import { useFormContext } from 'react-hook-form'

import { AUTH_METHOD_TYPE } from 'dbaas/features/Organization'
import { CentralOrgAuthMethod, CentralOrgDomain } from 'dbaas/services/account/interface'
import { domainRegEx } from 'dbaas/utils/regex'

import { CopyURL } from './CopyURL'
import { SCIMSettings } from './SCIM'

export { CopyURL } from './CopyURL'

const OIDCSettings = () => {
  const { watch } = useFormContext()
  const callbackUrl = watch('callback_url')
  return (
    <>
      <FormTextInput
        leftLabel={
          <Typography variant="label-lg" c="carbon.7">
            https://
          </Typography>
        }
        rightLabel={
          <Typography variant="label-lg" c="carbon.7">
            /.well-known/openid-configuration
          </Typography>
        }
        name="oidc_config.issuer_url"
        label="Issuer URL"
        rules={{
          required: 'Required'
        }}
        mt={16}
      />
      <FormTextInput
        label={<Typography variant="title-md">Client ID</Typography>}
        name="oidc_config.client_id"
        rules={{
          required: 'Required'
        }}
        mt={16}
      />
      <FormPasswordInput
        name="oidc_config.client_secret"
        label={<Typography variant="title-md">Client Secret</Typography>}
        mt={16}
        rules={{
          required: 'Required'
        }}
        // use new-password disabled auto fill password
        autoComplete="new-password"
      />
      <Typography variant="title-md" mt={16}>
        Callback URL
      </Typography>
      <CopyURL mt={8} value={callbackUrl || ''} />
    </>
  )
}

const SAMLSettings = () => {
  const { watch } = useFormContext()
  const postBackUrl = watch('saml_post_back_url')
  const entityId = watch('saml_entity_id')

  return (
    <>
      <Typography variant="title-md" mt={16}>
        Postback URL
      </Typography>
      <CopyURL mt={8} value={postBackUrl || ''} />
      <Typography variant="title-md" mt={16}>
        Entity ID
      </Typography>
      <CopyURL mt={8} value={entityId || ''} />
      <FormTextInput
        label={<Typography variant="title-md">Sign on URL</Typography>}
        name="saml_config.sign_on_url"
        mt={16}
        rules={{
          required: 'Required'
        }}
      />
      <FormTextareaInput
        label={<Typography variant="title-md">Signing Certificate</Typography>}
        name="saml_config.signing_cert"
        autosize
        minRows={6}
        maxRows={6}
        styles={{
          input: {
            lineHeight: 1.2
          }
        }}
        rules={{
          required: 'Required',
          validate: (value: string) => {
            if (!value) {
              return 'Required'
            }
            if (!value.startsWith('-----BEGIN CERTIFICATE-----') || !value.endsWith('-----END CERTIFICATE-----')) {
              return 'Paste the entire certificate from your IdP, including the lines -begin certificate- and -end certificate-.'
            }
            return true
          }
        }}
        mt={16}
        mb={8}
      />
    </>
  )
}

const BasicSettings: React.FC<React.PropsWithChildren<{ type: string }>> = ({ type }) => {
  const isOIDC = type === AUTH_METHOD_TYPE.OIDC
  const isSAML = type === AUTH_METHOD_TYPE.SAML

  return (
    <div>
      <Typography variant="title-md">Name</Typography>
      <Typography variant="body-lg">
        The name will be displayed on the login button for this method on your organization's login page.
      </Typography>
      <FormTextInput
        name="name"
        rules={{ required: 'Required', maxLength: { value: 50, message: 'Name must be 1~50 characters.' } }}
        disabled={!isOIDC && !isSAML}
        mt={8}
      />
      <FormTextInput label={<Typography variant="title-md">Type</Typography>} name="type" disabled mt={16} />
      {isOIDC && <OIDCSettings />}
      {isSAML && <SAMLSettings />}
    </div>
  )
}

const normalizeDomain = (value: string) => value.trim().toLowerCase()

export const normalizeAllowedEmailDomains = (value?: string) =>
  (value || '')
    .split(',')
    .map(normalizeDomain)
    .filter((it) => !!it)

const getVerifiedDomainNameSet = (domains: CentralOrgDomain[]) =>
  new Set(
    domains
      .filter((domain) => domain.status === 'verified')
      .map((domain) => normalizeDomain(domain.domain_name || ''))
      .filter(Boolean)
  )

const AddtionalSettings: React.FC<React.PropsWithChildren<{ type: string; domains: CentralOrgDomain[] }>> = ({
  type,
  domains
}) => {
  const { watch } = useFormContext()
  const isOIDC = type === AUTH_METHOD_TYPE.OIDC
  const isSAML = type === AUTH_METHOD_TYPE.SAML
  const autoProvision = watch('auto_provision')
  const scimProvision = watch('scim_provision')
  const isAllowedDomainRequired = isOIDC ? autoProvision : isSAML && (autoProvision || scimProvision)
  const verifiedDomainNameSet = getVerifiedDomainNameSet(domains)

  return (
    <div>
      <FormSwitch
        name="auto_provision"
        labelPosition="left"
        label={<Typography variant="title-md">Auto-provision Accounts</Typography>}
        styles={{
          labelWrapper: {
            flex: 1
          }
        }}
      />
      <Typography variant="body-lg" maw={434}>
        Automatically create a TiDB Cloud account when a user login for the first time.
      </Typography>
      <Typography variant="title-md" mt={24}>
        Allowed Email Domains
      </Typography>
      <Typography variant="body-lg">
        Only the specified email domains will be allowed to use this authentication method. Exclude the @ symbol when
        entering an email domain. Multiple email domains should be comma-separated.
      </Typography>
      <FormTextInput
        name="allow_email_domain_str"
        placeholder="ExampleDomain1.com, ExampleDomain2.com"
        rules={{
          validate: (value: string) => {
            const values = normalizeAllowedEmailDomains(value)

            if (values.length === 0) {
              if (isAllowedDomainRequired) {
                return 'Required'
              }
              return true
            }
            if (values.some((val) => !domainRegEx.test(val))) {
              return 'Invalid email domain'
            }
            if ((isOIDC || isSAML) && values.some((val) => !verifiedDomainNameSet.has(val))) {
              return 'Domain must be added and verified in Domains first'
            }
            return true
          }
        }}
        mt={16}
      />
      {type === AUTH_METHOD_TYPE.SAML && <SCIMSettings />}
    </div>
  )
}

export interface SettingsFormData extends CentralOrgAuthMethod {
  allow_email_domain_str?: string
  callback_url?: string
  saml_entity_id?: string
  saml_post_back_url?: string
  scim_connector_base_url?: string
  scim_supported_provisioning_actions?: string[]
  scim_unique_identifier_field?: string
}

export interface SettingsProps {
  opened: boolean
  onClose: () => void
  method: SettingsFormData
  domains: CentralOrgDomain[]
  onSubmit: (data: SettingsFormData) => Promise<void>
}

export const isMethodConfigured = (data: SettingsFormData) => {
  const { type = '' } = data
  if (
    (type === AUTH_METHOD_TYPE.OIDC && !data.oidc_config?.issuer_url) ||
    (type === AUTH_METHOD_TYPE.SAML && !data.saml_config?.sign_on_url)
  ) {
    return false
  }
  return true
}

export const Settings: React.FC<React.PropsWithChildren<SettingsProps>> = ({
  opened,
  onClose,
  method,
  domains,
  onSubmit
}) => {
  const { type = '' } = method
  const isActivate = !isMethodConfigured(method)

  return (
    <Drawer
      trapFocus={false}
      title={
        <Typography variant="title-lg" c="carbon.9">
          Authentication Method Details
        </Typography>
      }
      position="right"
      size={560}
      opened={opened}
      styles={() => ({
        drawer: {
          display: 'flex',
          flexDirection: 'column'
        },
        header: {
          padding: '20px 24px',
          marginBottom: 0
        },
        body: {
          padding: 0,
          flex: 1,
          overflowY: 'auto'
        }
      })}
      onClose={onClose}
    >
      <Form<SettingsFormData>
        sx={() => ({ height: '100%', display: 'flex', flexDirection: 'column' })}
        onSubmit={onSubmit}
        defaultValues={{ ...method }}
        errorMessageProps={{
          mx: 16
        }}
        onCancel={onClose}
        actionsProps={{
          sx(theme) {
            return {
              padding: 16,
              borderTop: `1px solid ${theme.colors.carbon[4]}`
            }
          },
          confirmText: isActivate ? 'Activate' : 'Save'
        }}
        layout="none"
      >
        <Accordion
          multiple
          defaultValue={['basic', 'additional']}
          // why using sx here?
          // root is not work in styles, there is no `root` in styles
          sx={() => ({ flex: 1, overflowY: 'auto' })}
          styles={(theme) => ({
            control: {
              padding: '8px 24px',
              backgroundColor: theme.colors.carbon[2]
            },
            content: {
              padding: 24,
              paddingTop: 16
            }
          })}
        >
          <Accordion.Item value="basic">
            <Accordion.Control>
              <Typography variant="action-md" c="carbon.9">
                Basic Settings
              </Typography>
            </Accordion.Control>
            <Accordion.Panel>
              <BasicSettings type={type} />
            </Accordion.Panel>
          </Accordion.Item>
          <Accordion.Item value="additional">
            <Accordion.Control>
              <Typography variant="action-md" c="carbon.9">
                Additional Settings
              </Typography>
            </Accordion.Control>
            <Accordion.Panel>
              <AddtionalSettings type={type} domains={domains} />
            </Accordion.Panel>
          </Accordion.Item>
        </Accordion>
      </Form>
    </Drawer>
  )
}
