import { ErrorMessage } from '@hookform/error-message'
import {
  ActionIcon,
  Box,
  Button,
  Card,
  Flex,
  Group,
  Input,
  InputBaseProps,
  SimpleGrid,
  Transition,
  Typography
} from '@tidbcloud/uikit'
import { Form, FormTextareaInput } from '@tidbcloud/uikit/biz'
import { IconFaceSad, IconFaceSmile, IconXClose } from '@tidbcloud/uikit/icons'
import dayjs from 'dayjs'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Controller, useForm, useFormContext, type RegisterOptions } from 'react-hook-form'
import { matchPath, useLocation } from 'react-router-dom'

import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'
import feedbackSuccessImg from 'media/feedback-success.png'

import {
  getOneConsoleFeedbackCompletedQuestions,
  getOneConsoleFeedbackDeadline,
  hasCompletedAllOneConsoleFeedbackEvents,
  LEGACY_FEEDBACK_ACC_KEY,
  LEGACY_FEEDBACK_MODAL_KEY,
  markOneConsoleFeedbackOnboardingStarted,
  markOneConsoleFeedbackDismissed,
  markOneConsoleFeedbackEventCompleted,
  markOneConsoleFeedbackShown,
  markOneConsoleFeedbackSubmitted,
  ONE_CONSOLE_FEEDBACK_EARLY_TRIGGER_DELAY_MS,
  ONE_CONSOLE_FEEDBACK_EVENT_KEYS,
  ONE_CONSOLE_FEEDBACK_STATE_EVENT,
  readOneConsoleFeedbackState,
  resetOneConsoleFeedbackState,
  type OneConsoleFeedbackEventKey
} from './feedbackState'
import { getShowGuideFlagFromSearch } from './getShowGuideFlagFromSearch'

interface FormScoreSelectProps extends InputBaseProps {
  name: string
  rules?: RegisterOptions
  onChange?: (value: number) => void
  count?: number
}

interface FeedbackAnswer {
  score?: number
  description?: string
}

interface FeedbackFormValues {
  myTidb: FeedbackAnswer
  creation: FeedbackAnswer
  move: FeedbackAnswer
}

interface FeedbackQuestion {
  key: OneConsoleFeedbackEventKey
  title: string
  description: string
  placeholder: string
}

const FEEDBACK_QUESTIONS: Record<OneConsoleFeedbackEventKey, FeedbackQuestion> = {
  myTidb: {
    key: 'myTidb',
    title: "How's the new My TiDB page?",
    description: 'Does the new resource center make managing your clusters and instances easier?',
    placeholder: "Any thoughts or roasts? We're all ears."
  },
  creation: {
    key: 'creation',
    title: 'How was the creation experience?',
    description: 'Was it easy to set up your Cluster or TiDB X Instance?',
    placeholder: 'Share your feedback with us?'
  },
  move: {
    key: 'move',
    title: 'How was the move?',
    description: 'How satisfied are you with the experience of moving your instance between projects?',
    placeholder: 'Tell us how we can improve?'
  }
}

const FEEDBACK_STEP_ORDER: OneConsoleFeedbackEventKey[] = ['myTidb', 'creation', 'move']

const createDefaultValues = (): FeedbackFormValues => ({
  myTidb: {
    score: undefined,
    description: ''
  },
  creation: {
    score: undefined,
    description: ''
  },
  move: {
    score: undefined,
    description: ''
  }
})

export const FormScoreSelect: React.FC<FormScoreSelectProps> = ({
  name,
  rules,
  onChange,
  count = 10,
  label,
  labelProps
}) => {
  const { control, formState, getFieldState } = useFormContext()
  const { error } = getFieldState(name, formState)
  const radius = 8

  return (
    <Controller
      control={control}
      name={name}
      rules={rules}
      render={({ field }) => {
        const { onChange: handleChange, value } = field
        const selected = value !== undefined
        return (
          <Box sx={{ width: '100%' }}>
            {label && <Input.Label {...labelProps}>{label}</Input.Label>}
            <SimpleGrid cols={count} sx={() => ({ borderRadius: 4 })} spacing={0}>
              {Array.from({ length: count }).map((_, index) => {
                const isFirst = index === 0
                const isLast = index === count - 1
                const active = value === index + 1
                const isPrev = selected && value - 1 === index + 1
                return (
                  <Flex
                    key={index.toString()}
                    align="center"
                    justify="center"
                    sx={(theme) => ({
                      border: `1px solid ${theme.colors.carbon[4]}`,
                      borderLeftWidth: 0,
                      cursor: 'pointer',
                      ...(isFirst
                        ? {
                            borderLeftWidth: 1,
                            borderTopLeftRadius: radius,
                            borderBottomLeftRadius: radius
                          }
                        : undefined),
                      ...(isLast
                        ? {
                            borderTopRightRadius: radius,
                            borderBottomRightRadius: radius
                          }
                        : undefined),
                      ...(active
                        ? {
                            backgroundColor: theme.colors.carbon[9],
                            color: theme.colors.carbon[1],
                            borderLeftWidth: 1,
                            borderColor: theme.colors.carbon[9]
                          }
                        : undefined),
                      ...(isPrev ? { borderRightColor: 'transparent' } : undefined)
                    })}
                    h={32}
                    onClick={() => {
                      handleChange(index + 1)
                      onChange?.(index + 1)
                    }}
                  >
                    <Typography variant="body-lg" c={active ? 'white' : 'carbon.8'}>
                      {index + 1}
                    </Typography>
                  </Flex>
                )
              })}
            </SimpleGrid>
            {error ? (
              <Input.Error>
                <ErrorMessage errors={formState.errors} name={name} />
              </Input.Error>
            ) : undefined}
          </Box>
        )
      }}
    />
  )
}

export const NewNavGuideFeedbackModal = () => {
  const location = useLocation()
  const {
    store: {
      userProfile: { id: userId }
    }
  } = useStores()

  const [opened, setOpened] = useState(false)
  const [activeStep, setActiveStep] = useState(0)
  const [questionKeys, setQuestionKeys] = useState<OneConsoleFeedbackEventKey[]>([])
  const [triggerType, setTriggerType] = useState<'early' | 'time' | undefined>()
  const [showSuccess, setShowSuccess] = useState(false)
  const openTimeoutRef = useRef<number>()
  const successTimeoutRef = useRef<number>()
  const openingModalRef = useRef(false)
  const forcedFeedbackOpenedRef = useRef(false)
  const form = useForm<FeedbackFormValues>({
    defaultValues: createDefaultValues()
  })

  const currentQuestionKey = questionKeys[activeStep]
  const currentQuestion = currentQuestionKey ? FEEDBACK_QUESTIONS[currentQuestionKey] : undefined
  const currentScore = currentQuestionKey ? form.watch(`${currentQuestionKey}.score` as const) : undefined
  const isLastStep = activeStep === questionKeys.length - 1
  const currentQuestionIndex = currentQuestionKey ? FEEDBACK_STEP_ORDER.indexOf(currentQuestionKey) : -1
  const isTidbsIndexRoute = !!matchPath(location.pathname, {
    path: '/tidbs',
    exact: true
  })
  const shouldForceShowFeedback = new URLSearchParams(location.search).get('showFeedback') === '1'

  const closeModal = useCallback(() => {
    window.clearTimeout(openTimeoutRef.current)
    setOpened(false)
    setActiveStep(0)
  }, [])

  const openModal = useCallback(
    (nextQuestionKeys: OneConsoleFeedbackEventKey[], nextTriggerType?: 'early' | 'time') => {
      if (!userId) {
        return
      }

      openingModalRef.current = true
      markOneConsoleFeedbackShown(userId)
      form.reset(createDefaultValues())
      setQuestionKeys(nextQuestionKeys)
      setActiveStep(0)
      setTriggerType(nextTriggerType)
      setOpened(true)
      openingModalRef.current = false
    },
    [form, userId]
  )

  const evaluateTrigger = useCallback(
    (source: 'event' | 'visit') => {
      if (!userId || opened || openingModalRef.current) {
        return
      }

      const state = readOneConsoleFeedbackState(userId)
      const deadline = getOneConsoleFeedbackDeadline(state)
      const completedQuestions = getOneConsoleFeedbackCompletedQuestions(state)

      if (!state.onboardingStartedAt || !deadline || !completedQuestions.length) {
        return
      }
      if (state.shownAt || state.dismissedAt || state.submittedAt) {
        return
      }

      const now = dayjs()
      const shouldEarlyTrigger =
        source === 'event' && now.isBefore(deadline) && hasCompletedAllOneConsoleFeedbackEvents(state)
      const shouldTimeTrigger = source === 'visit' && !now.isBefore(deadline)

      if (!shouldEarlyTrigger && !shouldTimeTrigger) {
        return
      }

      const nextQuestionKeys = shouldEarlyTrigger ? [...ONE_CONSOLE_FEEDBACK_EVENT_KEYS] : completedQuestions

      window.clearTimeout(openTimeoutRef.current)
      if (shouldEarlyTrigger) {
        openTimeoutRef.current = window.setTimeout(() => {
          openModal(nextQuestionKeys, 'early')
        }, ONE_CONSOLE_FEEDBACK_EARLY_TRIGGER_DELAY_MS)
        return
      }

      openModal(nextQuestionKeys, 'time')
    },
    [openModal, opened, userId]
  )

  const handleDismiss = useCallback(() => {
    if (!userId) {
      closeModal()
      return
    }

    markOneConsoleFeedbackDismissed(userId)
    eventTracking('One Console Feedback Modal Cancel', {
      triggerType,
      questions: questionKeys.join(',')
    })
    closeModal()
  }, [closeModal, questionKeys, triggerType, userId])

  const handleSubmit = useCallback(
    (values: FeedbackFormValues) => {
      if (!currentQuestionKey || !userId) {
        closeModal()
        return
      }

      if (!isLastStep) {
        setActiveStep((prev) => prev + 1)
        return
      }

      const state = readOneConsoleFeedbackState(userId)
      const answers = questionKeys.reduce<Record<string, string | number>>((acc, key) => {
        const answer = values[key]
        if (answer.score !== undefined) {
          acc[`${key}Score`] = answer.score
        }
        if (answer.description?.trim()) {
          acc[`${key}Description`] = answer.description.trim()
        }
        return acc
      }, {})

      eventTracking('One Console Feedback Submit', {
        triggerType,
        onboardingStartedAt: state.onboardingStartedAt,
        questions: questionKeys.join(','),
        ...answers
      })
      markOneConsoleFeedbackSubmitted(userId)
      closeModal()

      setShowSuccess(true)
      window.clearTimeout(successTimeoutRef.current)
      successTimeoutRef.current = window.setTimeout(() => {
        setShowSuccess(false)
      }, 3000)
    },
    [closeModal, currentQuestionKey, isLastStep, questionKeys, triggerType, userId]
  )

  useEffect(() => {
    return () => {
      window.clearTimeout(successTimeoutRef.current)
    }
  }, [])

  useEffect(() => {
    if (!userId) {
      return
    }

    if (shouldForceShowFeedback) {
      if (!forcedFeedbackOpenedRef.current) {
        forcedFeedbackOpenedRef.current = true
        openModal([...ONE_CONSOLE_FEEDBACK_EVENT_KEYS])
      }
      return
    }

    forcedFeedbackOpenedRef.current = false

    if (getShowGuideFlagFromSearch(location.search)) {
      resetOneConsoleFeedbackState(userId)
      window.localStorage.removeItem(LEGACY_FEEDBACK_ACC_KEY)
      window.localStorage.removeItem(LEGACY_FEEDBACK_MODAL_KEY)
      closeModal()
      return
    }

    evaluateTrigger('visit')
  }, [closeModal, evaluateTrigger, location.search, openModal, shouldForceShowFeedback, userId])

  useEffect(() => {
    if (!userId || !isTidbsIndexRoute) {
      return
    }

    markOneConsoleFeedbackOnboardingStarted(userId)
    markOneConsoleFeedbackEventCompleted(userId, 'myTidb')
    evaluateTrigger('event')
  }, [evaluateTrigger, isTidbsIndexRoute, userId])

  useEffect(() => {
    const handleFeedbackStateUpdate = (event: Event) => {
      const customEvent = event as CustomEvent<{ userId?: string }>
      if (customEvent.detail?.userId && customEvent.detail.userId !== userId) {
        return
      }

      evaluateTrigger('event')
    }

    window.addEventListener(ONE_CONSOLE_FEEDBACK_STATE_EVENT, handleFeedbackStateUpdate)

    return () => {
      window.removeEventListener(ONE_CONSOLE_FEEDBACK_STATE_EVENT, handleFeedbackStateUpdate)
      window.clearTimeout(openTimeoutRef.current)
    }
  }, [evaluateTrigger, userId])

  if (!currentQuestion) {
    return null
  }

  return (
    <Box
      sx={{
        position: 'fixed',
        right: 24,
        bottom: 24,
        zIndex: 101
      }}
    >
      <Transition mounted={opened} transition="fade-up" duration={400} timingFunction="ease">
        {(styles) => (
          <Card
            style={styles}
            w={400}
            h={310}
            p={24}
            radius={16}
            data-testid="new-nav-guide-feedback-modal"
            sx={{ display: 'flex', flexDirection: 'column' }}
          >
            <Form<FeedbackFormValues>
              form={form}
              onSubmit={handleSubmit}
              withActions={false}
              layoutProps={{ gap: 16, sx: { height: '100%' } }}
            >
              <Typography variant="headline-md" sx={{ fontSize: 20, lineHeight: '30px' }}>
                {currentQuestion.title}
              </Typography>
              <Typography variant="body-lg" mt={-8}>
                {currentQuestion.description}
              </Typography>
              <Group justify="space-between">
                <IconFaceSad size={24} c="carbon.8" strokeWidth={1} />
                <IconFaceSmile size={24} c="carbon.8" strokeWidth={1} />
              </Group>
              <FormScoreSelect
                key={`${currentQuestion.key}-score`}
                name={`${currentQuestion.key}.score`}
                count={10}
                rules={{ required: 'Please rate your experience.' }}
              />
              <FormTextareaInput
                key={`${currentQuestion.key}-description`}
                name={`${currentQuestion.key}.description`}
                placeholder={currentQuestion.placeholder}
                minRows={1}
                autosize
                styles={{
                  input: {
                    minHeight: 32
                  }
                }}
              />
              <Group justify="space-between">
                <Group gap={12}>
                  {FEEDBACK_STEP_ORDER.map((key, index) => (
                    <Box
                      key={key}
                      w={8}
                      h={8}
                      sx={(theme) => ({
                        borderRadius: '50%',
                        backgroundColor:
                          currentQuestionIndex >= 0 && index <= currentQuestionIndex
                            ? theme.colors.carbon[8]
                            : theme.colors.carbon[4]
                      })}
                    />
                  ))}
                </Group>
                <Group gap="sm">
                  <Button
                    variant="default"
                    h={32}
                    px={12}
                    onClick={handleDismiss}
                    data-testid="new-nav-guide-feedback-dismiss"
                  >
                    Not Now
                  </Button>
                  <Button
                    type="submit"
                    h={32}
                    px={12}
                    disabled={!currentScore}
                    data-testid="new-nav-guide-feedback-submit"
                  >
                    {isLastStep ? 'Submit' : 'Next'}
                  </Button>
                </Group>
              </Group>
            </Form>
          </Card>
        )}
      </Transition>

      <Transition mounted={showSuccess} transition="fade-up" duration={400} timingFunction="ease">
        {(styles) => (
          <Card
            style={styles}
            w={302}
            h={148}
            p={20}
            radius={12}
            data-testid="new-nav-guide-feedback-success"
            sx={{
              position: 'absolute',
              bottom: 0,
              right: 0,
              boxShadow: '0px 4px 16px rgba(0, 0, 0, 0.08)'
            }}
          >
            <ActionIcon
              onClick={() => setShowSuccess(false)}
              sx={{ position: 'absolute', top: 8, right: 8 }}
              variant="subtle"
              color="carbon.6"
              size="sm"
            >
              <IconXClose size={16} />
            </ActionIcon>
            <Flex align="center" justify="center" gap={16} h="100%">
              <img src={feedbackSuccessImg} alt="Success" width={62} height={62} style={{ objectFit: 'contain' }} />
              <Typography fw={700} c="carbon.7" sx={{ fontSize: 20, lineHeight: '30px' }}>
                Thanks for helping us grow!
              </Typography>
            </Flex>
          </Card>
        )}
      </Transition>
    </Box>
  )
}
