import { ActionIcon, Box, Center, Flex, Loader, useComputedColorScheme } from '@tidbcloud/uikit'
import { IconCube01, IconExpand03, IconScaleDown } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { PropsWithChildren, useCallback, useEffect, useRef, useState } from 'react'

import config from 'config'
import { useGetExpWhiteList } from 'dbaas/services'
import { ExpFeatHashmap } from 'dbaas/stores/localStorage'
import useStores from 'dbaas/stores/useStores'
import { MixpanelEvents } from 'dbaas/utils/tracking'

import { EntryCard, HelpCenterCard } from '../CenterCard'
import { CenterBreadcrumbs } from '../CenterRoute'
import { DEFAULT_HELP_PATH, useHelpCenterContext } from '../context'

export const AGENT_BASE_PATH = `${DEFAULT_HELP_PATH}/agent`

const TIPILOT_MESSAGE_CHANNEL = 'tidbcloud.tipilot'
const TIPILOT_MESSAGE_VERSION = 1
const TIPILOT_APPEARANCE_UPDATE = 'tidbcloud.appearance.update'

type TipilotTheme = 'light' | 'dark'

interface TipilotAppearanceMessage {
  channel: typeof TIPILOT_MESSAGE_CHANNEL
  version: typeof TIPILOT_MESSAGE_VERSION
  type: typeof TIPILOT_APPEARANCE_UPDATE
  payload: {
    theme: TipilotTheme
  }
}

const createTipilotAppearanceMessage = (theme: TipilotTheme): TipilotAppearanceMessage => ({
  channel: TIPILOT_MESSAGE_CHANNEL,
  version: TIPILOT_MESSAGE_VERSION,
  type: TIPILOT_APPEARANCE_UPDATE,
  payload: { theme }
})

export const useAgentHelpCenterAvailability = () => {
  const { dialogOpened } = useHelpCenterContext()
  const {
    store: { tenantData }
  } = useStores()
  const {
    data: isAgentWhitelisted = false,
    isFetched,
    isFetching
  } = useGetExpWhiteList(tenantData.id, undefined, {
    query: {
      enabled: Boolean(config.AGENT_IFRAME_URL && tenantData.id && dialogOpened),
      select: (whiteList) => whiteList?.exp_names?.includes(ExpFeatHashmap.InvestibookOnConsole) ?? false,
      refetchOnWindowFocus: false
    }
  })

  const enabled = Boolean(config.AGENT_IFRAME_URL && isAgentWhitelisted)
  const resolved = Boolean(!config.AGENT_IFRAME_URL || !tenantData.id || (isFetched && !isFetching))

  return { enabled, resolved }
}

export const AgentHelpCenterEntry = () => {
  const { setCurrentPath } = useHelpCenterContext()

  return (
    <EntryCard
      title="Chat with Investibook for Diagnosis"
      avatar={<IconCube01 size={20} c="sky.7" strokeWidth={1.5} />}
      avatarProps={{
        styles: (theme) => ({
          placeholder: {
            backgroundColor: theme.colors.sky[2]
          }
        })
      }}
      onClick={() => setCurrentPath(AGENT_BASE_PATH)}
      dataTestId="agent-entry"
      dataMpEvent={MixpanelEvents.HelpCenterAgent.View.ButtonClicked}
    />
  )
}

export const AgentPanel = observer(() => {
  const { agentPanelExpanded, setAgentPanelExpanded } = useHelpCenterContext()
  const {
    store: { tenantData }
  } = useStores()
  const theme = useComputedColorScheme()
  const iframeRef = useRef<HTMLIFrameElement>(null)
  const iframeIdentity = `${config.AGENT_IFRAME_URL}:${tenantData.id}`
  const iframeDescriptorRef = useRef<{ identity: string; origin: string; url: string }>()
  const lastSentAppearanceRef = useRef<{ identity: string; theme: TipilotTheme }>()
  const [loadedIframeIdentity, setLoadedIframeIdentity] = useState('')

  if (iframeDescriptorRef.current?.identity !== iframeIdentity) {
    const agentIframeUrl = new URL(config.AGENT_IFRAME_URL)

    if (tenantData.id) {
      agentIframeUrl.searchParams.set('orgId', tenantData.id)
    }
    agentIframeUrl.searchParams.set('theme', theme)

    iframeDescriptorRef.current = {
      identity: iframeIdentity,
      origin: agentIframeUrl.origin,
      url: agentIframeUrl.toString()
    }
  }

  const iframeDescriptor = iframeDescriptorRef.current
  const loading = loadedIframeIdentity !== iframeDescriptor.identity
  const postAppearance = useCallback(
    (nextTheme: TipilotTheme) => {
      const targetWindow = iframeRef.current?.contentWindow
      if (!targetWindow) {
        return
      }

      targetWindow.postMessage(createTipilotAppearanceMessage(nextTheme), iframeDescriptor.origin)
      lastSentAppearanceRef.current = { identity: iframeDescriptor.identity, theme: nextTheme }
    },
    [iframeDescriptor]
  )

  useEffect(() => {
    const lastSentAppearance = lastSentAppearanceRef.current
    if (
      loadedIframeIdentity === iframeDescriptor.identity &&
      (lastSentAppearance?.identity !== iframeDescriptor.identity || lastSentAppearance.theme !== theme)
    ) {
      postAppearance(theme)
    }
  }, [iframeDescriptor.identity, loadedIframeIdentity, postAppearance, theme])

  const handleIframeLoad = () => {
    postAppearance(theme)
    setLoadedIframeIdentity(iframeDescriptor.identity)
  }

  return (
    <Flex direction="column" h="100%" data-testid="agent-panel">
      <HelpCenterCard.Header
        rightSection={
          <ActionIcon
            variant="transparent"
            c="carbon.8"
            aria-label={agentPanelExpanded ? 'Scale down Investibook panel' : 'Scale up Investibook panel'}
            data-testid={agentPanelExpanded ? 'agent-panel-scale-down' : 'agent-panel-scale-up'}
            data-mp-event={MixpanelEvents.HelpCenterAgent.Operate.ButtonClicked}
            data-mp-action={agentPanelExpanded ? 'scale_down' : 'scale_up'}
            onClick={() => setAgentPanelExpanded(!agentPanelExpanded)}
          >
            {agentPanelExpanded ? <IconScaleDown size={12} /> : <IconExpand03 size={12} />}
          </ActionIcon>
        }
      >
        <CenterBreadcrumbs
          items={[
            { path: DEFAULT_HELP_PATH, title: 'Help' },
            { path: AGENT_BASE_PATH, title: 'Investibook' }
          ]}
        />
      </HelpCenterCard.Header>
      <HelpCenterCard.Content p={0}>
        <Box h="100%" sx={{ position: 'relative', overflow: 'hidden' }}>
          {loading && (
            <Center
              data-testid="agent-loading"
              sx={(theme) => ({
                position: 'absolute',
                inset: 0,
                zIndex: 1,
                backgroundColor: theme.colors.carbon[0]
              })}
            >
              <Loader />
            </Center>
          )}
          <iframe
            key={iframeDescriptor.identity}
            ref={iframeRef}
            data-testid="agent-iframe"
            title="Investibook"
            src={iframeDescriptor.url}
            sandbox="allow-scripts allow-forms allow-same-origin allow-downloads"
            allow="clipboard-write"
            referrerPolicy="no-referrer"
            onLoad={handleIframeLoad}
            style={{
              display: 'block',
              width: '100%',
              height: '100%',
              border: 0
            }}
          />
        </Box>
      </HelpCenterCard.Content>
    </Flex>
  )
})

export const PersistentAgentPanel = observer(({ children, enabled }: PropsWithChildren<{ enabled: boolean }>) => {
  const { currentPath } = useHelpCenterContext()
  const {
    store: { tenantData }
  } = useStores()
  const [initializedOrgId, setInitializedOrgId] = useState('')
  const active = currentPath === AGENT_BASE_PATH

  useEffect(() => {
    if (!enabled) {
      setInitializedOrgId('')
    } else if (active && tenantData.id) {
      setInitializedOrgId(tenantData.id)
    }
  }, [active, enabled, tenantData.id])

  const initializedForCurrentOrg = Boolean(tenantData.id && initializedOrgId === tenantData.id)
  const mounted = enabled && (active || initializedForCurrentOrg)

  if (!mounted) {
    return null
  }

  return (
    <Box
      h="100%"
      display={active ? 'block' : 'none'}
      aria-hidden={!active}
      data-testid="agent-panel-host"
      sx={{ flex: 1, minHeight: 0 }}
    >
      {children}
    </Box>
  )
})
