import { Button } from 'antd'
import ConfirmDeleteModal from 'components/ConfirmDeleteModal'
import PublishModal from 'components/PublishModal'
import { Text } from 'components/Typography'
import { MINUTES } from 'constants/date'
import { SEGMENT_EVENTS } from 'constants/segment'
import firebase from 'firebase'
import { useAnalytics } from 'hooks/useAnalytics'
import reduce from 'lodash/reduce'
import debounce from 'lodash/debounce'
import isEmpty from 'lodash/isEmpty'
import omit from 'lodash/omit'
import pick from 'lodash/pick'
import uniq from 'lodash/uniq'
import { useToast } from '@komi-app/creator-ui'
import { FLAGS, IfFeature, useFeatureIsOn } from '@komi-app/flags-sdk'

import moment from 'moment'
import React, {
  createContext,
  useCallback,
  useEffect,
  useMemo,
  useState
} from 'react'
import { useDispatch } from 'react-redux'
import { useHistory, useLocation } from 'react-router-dom'
import { useTypedSelector } from 'redux/rootReducer'
import { setActiveModuleAction } from 'redux/Talent/actions'
import {
  autoSaveProfileActions,
  deleteLocalizationActions,
  forceSaveAndLogoutActions,
  forceSaveAndpublishProfileActions,
  getLocalizationModulesActions,
  getUserProfileActions,
  publishProfileActions,
  setIsPublishedActions,
  setLoadingAutoSaveActions,
  setLocalizationSelectedAction,
  setLocalizationUnpublishIdsAction
} from 'redux/User/actions'
import {
  selectCollaborator,
  selectIsBlockingEdit,
  selectIsCollaborator,
  selectIsPublished,
  selectLoadingAutoSave,
  selectLoadingDeleteLocalization,
  selectLocalizationActive,
  selectLocalizationSelected,
  selectLocalizationUnpublishIds,
  selectModuleLoading,
  selectPreviousModulesVersion,
  selectPreviousProfileVersion,
  selectTalentProfile,
  selectTalentProfileModules,
  selectUserData
} from 'redux/User/selector'
import {
  LocalizationItem,
  LocalizationItem as LocalizationItemType
} from 'redux/User/types'
import { firebaseService, authService } from 'services'
import { JSONService } from 'utils/json-patch'
import notification from 'utils/notification'
import { copyTextToClipboard } from '../../utils/copyTextToClipboard'
import { profileLink } from '../PreviewLayoutHeader/utils'
import {
  DigitalProductItem,
  SOMETHING_WENT_WRONG
} from '@komi-app/profiles-sdk'
import { useHasTemplates } from 'hooks/useHasTemplates'
import { TemplatePublishWarningModal } from 'components/TemplatePublishWarningModal/TemplatePublishWarningModal'
import When from '@komi-app/when'
import PrePublishModal from 'components/PrePublishModal'

import { ModuleType } from '@komi-app/shared-types'
import { useCreatorTracking, CreatorEvent } from '@komi-app/analytics-sdk'
import {
  TalentModuleMixItem,
  TalentProfileModule
} from '../../models/talent/talent-profile-module.model'

export interface IContext {
  localizationSelected: any
  setLocalizationSelected: (value: any) => void
  isVisiblePublish: boolean
  setIsVisiblePublish: (value: boolean) => void
  isChangePageLoading: boolean
  setIsChangePageLoading: (value: boolean) => void
  isSaving: boolean
  setIsSaving: (value: boolean) => void
  isBlockingEditState: boolean
  setIsBlockingEditState: (value: boolean) => void
  setVisibleConfirmPublish: (value: boolean) => void
  onCheckBeforeChangeRouter: (location: any) => any
  onPublish: (localizationId?: any[]) => void
  handleChangeLocalization: (value: LocalizationItem) => void
  onForceSave: (callback?: any) => void
  onSaveProfile: (options: SaveProfileOptions) => void
  onDeleteLocalization: (localizationId: string | null, page: any) => void
}

export type SaveProfileOptions = {
  newTalent?: any
  newModules?: any
  localizationId?: any
  callback?: () => void
  errorCallback?: () => void
  cancel?: boolean
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
export const AutoSaveContext = createContext<IContext>(null!)

const DARK_COLOR = '#121212'

const DEFAULT_PAGE = {
  id: null,
  name: 'Default',
  currency: 'USD',
  active: false,
  countries: [],
  copyFrom: null,
  isPublished: false
}

interface AutoSaveProviderProps {
  children: React.ReactNode
}

export const AutoSaveProvider = ({ children }: AutoSaveProviderProps) => {
  const dispatch = useDispatch()
  const localizationSelected = useTypedSelector(selectLocalizationSelected)
  const [isVisiblePublish, setIsVisiblePublish] = useState<boolean>(false)
  const [visibleConfirmPublish, setVisibleConfirmPublish] =
    useState<boolean>(false)
  const [isChangePageLoading, setIsChangePageLoading] = useState<boolean>(false)
  const [isBlockingEditState, setIsBlockingEditState] = useState<boolean>(false)
  const router = useHistory()
  const location = useLocation<{ retainModules: boolean }>()

  const talentProfile = useTypedSelector(selectTalentProfile)
  const previousProfile = useTypedSelector(selectPreviousProfileVersion)
  const modules = useTypedSelector(selectTalentProfileModules)
  const previousModulesVersion = useTypedSelector(selectPreviousModulesVersion)
  const [isSaving, setIsSaving] = useState<boolean>(false)
  const user = useTypedSelector(selectUserData)
  const collaborator = useTypedSelector(selectCollaborator)
  const isCollaborator = useTypedSelector(selectIsCollaborator)
  const moduleLoading = useTypedSelector(selectModuleLoading)
  const loadingAutoSave = useTypedSelector(selectLoadingAutoSave)
  const loadingDeleteLocalization = useTypedSelector(
    selectLoadingDeleteLocalization
  )
  const { sendSegmentEvent } = useAnalytics()
  const isPublished = useTypedSelector(selectIsPublished)
  const isBlockingEdit = useTypedSelector(selectIsBlockingEdit)
  const [blocked, setBlocked] = useState(false)
  const localizationUnpublishIds = useTypedSelector(
    selectLocalizationUnpublishIds
  )
  const localizationActive = useTypedSelector(selectLocalizationActive)
  const hasTemplateModules = useHasTemplates()
  const isCopyUrlPromptFeatureEnabled = useFeatureIsOn(
    FLAGS.FEAT_SB_331_COPY_URL_PROMPT
  )
  const isTemplatesV2Enabled = useFeatureIsOn(
    FLAGS.FEAT_SB_447_MODULE_TEMPLATES
  )
  const useAnalyticsSDK = useFeatureIsOn(FLAGS.USE_ANALYTICS_SDK_TALENT)
  const { createTracker } = useCreatorTracking()
  const displayNameUpdated = createTracker(CreatorEvent.DISPLAY_NAME_UPDATED)
  const profilePhotoUpdated = createTracker(CreatorEvent.PROFILE_PHOTO_UPDATED)
  const themeUpdated = createTracker(CreatorEvent.THEME_UPDATED)
  const socialLinksUpdated = createTracker(CreatorEvent.SOCIAL_LINKS_UPDATED)
  const publishChanges = createTracker(CreatorEvent.PUBLISH_CHANGES)
  const useFreeDownload = useFeatureIsOn(FLAGS.FREE_DOWNLOADS_TALENT)

  const { createToast } = useToast()

  const attributeKey = useMemo(
    () => (talentProfile?.id ? `talent/${talentProfile?.id}` : null),
    [talentProfile?.id]
  )

  // Pick the properties off of the profile to be auto saved
  const pickProfileInfo = (talent: any) => {
    return pick(talent, [
      'avatar',
      'avatarRatio',
      'avatarFilename',
      'displayName',
      'displayNameImage',
      'displayNameImageScale',
      'displayNameType',
      'showDisplayName',
      'socialProfileLinks',
      'themeColor',
      'themeType',
      'profileUpdated'
    ])
  }

  // Checks if any changes have been made to the talent profile
  const isProfileUpdated = useMemo(() => {
    if (!talentProfile || !previousProfile) {
      return false
    }
    const currentProfile = pickProfileInfo(talentProfile)
    const preProfile = pickProfileInfo(previousProfile)

    // TODO: Work out exactly how `JSONService.getPatch` works. I suspect it's operating
    //   like a diff
    const patch = JSONService.getPatch(currentProfile, preProfile, {
      actions: ['add', 'remove', 'replace'],
      ignoreFields: ['modules']
    })

    // If the patch contains a name change, send a Segment event
    if (patch?.displayName || patch?.displayNameType) {
      const type = currentProfile?.displayNameType || 'None'

      useAnalyticsSDK
        ? displayNameUpdated({ type })
        : sendSegmentEvent(SEGMENT_EVENTS.DISPLAY_NAME_UPDATED, {
            'Display Name Type': type
          })
    }

    // If the patch contains a avatar change, send a Segment event
    if (patch?.avatar) {
      useAnalyticsSDK
        ? profilePhotoUpdated()
        : sendSegmentEvent(SEGMENT_EVENTS.PROFILE_PHOTO_UPDATED)
    }

    // If the patch contains a theme color or type change, send a Segment event for the change
    if (patch?.themeColor && !patch?.themeType) {
      let themUpdate = ''
      if (
        !!currentProfile?.themeColor?.backgroundColor &&
        !!preProfile?.themeColor?.backgroundColor &&
        currentProfile?.themeColor?.backgroundColor !==
          preProfile?.themeColor?.backgroundColor
      ) {
        themUpdate = 'Background Color Update'
      }

      if (
        !!currentProfile?.themeColor?.typographyColor &&
        !!preProfile?.themeColor?.typographyColor &&
        currentProfile?.themeColor?.typographyColor !==
          preProfile?.themeColor?.typographyColor
      ) {
        themUpdate = 'Typography Color Update'
      }

      if (
        !!currentProfile?.themeColor?.overlayColor &&
        !!preProfile?.themeColor?.overlayColor &&
        currentProfile?.themeColor?.overlayColor !==
          preProfile?.themeColor?.overlayColor
      ) {
        if (currentProfile.themeColor.overlayColor === DARK_COLOR) {
          themUpdate = 'Dark Overlay'
        } else {
          themUpdate = 'Light Overlay'
        }
      }

      const value = themUpdate

      useAnalyticsSDK
        ? themeUpdated({ value })
        : sendSegmentEvent(SEGMENT_EVENTS.THEME_UPDATED, {
            'Theme Update': value
          })
    }

    // If the theme type changes, send a Segment type
    if (patch?.themeType) {
      let themUpdate = 'Light Theme'
      switch (patch?.themeType) {
        case 'DARK':
          themUpdate = 'Dark Theme'
          break

        case 'CUSTOM':
          themUpdate = 'Custom Theme'
          break

        default:
          break
      }

      const value = themUpdate

      useAnalyticsSDK
        ? themeUpdated({ value })
        : sendSegmentEvent(SEGMENT_EVENTS.THEME_UPDATED, {
            'Theme Update': value
          })
    }

    // If the social profile link changes, send a Segment event
    if (patch?.socialProfileLinks) {
      useAnalyticsSDK
        ? socialLinksUpdated()
        : sendSegmentEvent(SEGMENT_EVENTS.SOCIAL_LINKS_UPDATED)
    }

    return !isEmpty(patch)
  }, [talentProfile, previousProfile, sendSegmentEvent])

  // Converts a module element into a module item, which presumably is a more generic type
  const getModuleItemByElement = useCallback((item, isGrouped?: boolean) => {
    const keys = [
      'isUpdate',
      'isEdit',
      'createdAt',
      'updatedAt',
      'localizationId',
      'deletedAt',
      'isCreate',
      'isLoading',
      'expand',
      'persistentId'
    ]
    if (!isGrouped) {
      keys.push('showTitle')
    }
    return omit(item, keys)
  }, [])

  // Checks if a module has been updated
  const isModuleUpdated = useMemo(() => {
    // Flatten the elements within groups and modules into module items
    const current = reduce(
      modules,
      (results: any, item: any) => {
        if (item.type === ModuleType.GROUP) {
          const items = item.items.map((element: any) =>
            getModuleItemByElement(element, true)
          )

          return [...results, getModuleItemByElement({ ...item, items }, false)]
        }
        return [...results, getModuleItemByElement(item, false)]
      },
      []
    )

    // Flatten the elements within groups and modules into module items
    const prev = reduce(
      previousModulesVersion,
      (results: any, item: any) => {
        if (item.type === ModuleType.GROUP) {
          const items = item.items.map((element: any) =>
            getModuleItemByElement(element, true)
          )

          return [...results, getModuleItemByElement({ ...item, items }, false)]
        }
        return [...results, getModuleItemByElement(item, false)]
      },
      []
    )

    // Get the difference between the two modules
    const modulesPatch = JSONService.getPatch(
      { items: current },
      { items: prev },
      {
        actions: ['add', 'remove', 'replace'],
        ignoreFields: []
      }
    )

    // If there is a difference, return true
    return !isEmpty(modulesPatch)
  }, [modules, previousModulesVersion])

  const setLocalizationSelected = useCallback(
    (locale: LocalizationItemType) => {
      return dispatch(setLocalizationSelectedAction(locale))
    },
    [dispatch]
  )

  // Retry notification
  const onNetworkError = (text = '', onRetry: any) => {
    notification.error({
      message: (
        <>
          <Text>{text}</Text>
          <Button type="text" className="m__l--32 p--0" onClick={onRetry}>
            <Text preset="medium16" className="text--blue">
              Retry
            </Text>
          </Button>
        </>
      ),
      key: 'auto-save-network-error',
      duration: 0
    })
  }

  // Updates the talent's last connection in Firebase
  const updateAttributesData = useCallback(
    async (data = {}) => {
      if (attributeKey) {
        try {
          const currentAttrs =
            (await firebaseService.getOnce(attributeKey)).val() || {}

          let newAttrs = {
            ...currentAttrs,
            ...data,
            [`${collaborator?.id ?? user?.id}`]: {
              lastConnection: moment().toISOString()
            }
          }
          if (currentAttrs?.startedAt) {
            newAttrs = {
              ...currentAttrs,
              talentLastConnection: moment().toISOString()
            }
          }
          await firebaseService.write(attributeKey, newAttrs)
        } catch (error) {
          console.error('error: ', error)
        }
      }
    },
    [attributeKey, collaborator?.id, user?.id, isCollaborator]
  )

  // Event handler for profile saving
  const onSaveProfile = useCallback(
    ({
      newTalent,
      newModules,
      localizationId,
      callback,
      errorCallback,
      cancel
    }: SaveProfileOptions) => {
      setIsSaving(false)
      if (cancel) {
        return
      }
      const newProfile = pickProfileInfo(newTalent)
      let digitalProductsFilesToUpload
      if (useFreeDownload && !!newModules) {
        digitalProductsFilesToUpload =
          getDigitalProductsFilesToUpload(newModules)
      }
      // Attempt to auto save the new profile
      dispatch(
        autoSaveProfileActions.REQUEST({
          localizationId,
          profile: newProfile,
          modules: newModules,
          //manually pass user that is doing update incase tab is changed and another user is logged in while autosaving
          updatedById: collaborator?.id ?? user?.id,
          //manually pass talent id, in the event that account has multiple talents and only the top one is used
          updateTalentId: talentProfile?.id,
          ...(digitalProductsFilesToUpload && { digitalProductsFilesToUpload }),
          onSuccess: () => {
            // Save the update data to Firebase
            updateAttributesData({
              lastEdit: {
                userId: collaborator?.id ?? user?.id,
                updatedAt: moment().toISOString()
              },
              isPublished: false
            })
            // This flag is set because if we change a profile setting and then set it back
            // The data in redux is exactly the same and switches back to the latest change
            // Which makes the profile jump around
            // Set in setTalentProfileType in User/reducer.ts
            newTalent.profileUpdated = false
            callback?.()
          },
          onNetworkError: () => {
            errorCallback?.()
            onNetworkError(
              'Changes could not be saved due to a network error.',
              // Callback for retry attempt on notification retry button click
              () => {
                notification.destroy('auto-save-network-error')
                onSaveProfile({
                  newTalent,
                  newModules,
                  localizationId: localizationSelected?.id
                })
              }
            )
          }
        })
      )
    },
    [
      isCollaborator,
      collaborator?.id,
      user?.id,
      updateAttributesData,
      dispatch,
      localizationSelected?.id
    ]
  )

  //Find and construct for all {[productId]: file} pair in the modules
  const getDigitalProductsFilesToUpload = (
    modules: TalentProfileModule<TalentModuleMixItem>[]
  ) => {
    return modules
      .flatMap(module => {
        if (module.type === ModuleType.GROUP) {
          return module.items as TalentProfileModule<TalentModuleMixItem>[]
        }

        return module
      })
      .reduce<Record<string, File | undefined>>((acc, module) => {
        if (
          [ModuleType.FREE_DOWNLOAD, ModuleType.DIGITAL_PRODUCT].includes(
            module.type as ModuleType
          )
        ) {
          ;(module.items as DigitalProductItem[]).forEach(item => {
            if (item.landingPage.isUploadFile) {
              acc[item.id] = item.file
            }
          })
        }
        return acc
      }, {})
  }

  // Auto save with a debounce
  const debounceAutoSave = useCallback(debounce(onSaveProfile, 15000), [
    updateAttributesData
  ])

  //
  const getIsPublishedStatus = useCallback(
    (localizationId: any[]) => {
      const isDefaultUpdated = localizationId.includes(null)
      const currentIds = localizationUnpublishIds?.filter(
        item => !localizationId.includes(item)
      )
      const newLocalizations = [...(talentProfile?.localizations || [])]?.map(
        item => {
          const isUpdated = localizationId.includes(item.id)
          return {
            ...item,
            isPublished: isUpdated ? true : item.isPublished,
            active: isUpdated ? true : item.active,
            isFirstTimePublished: isUpdated ? true : item.isFirstTimePublished
          }
        }
      )

      const versions = isDefaultUpdated ? [] : talentProfile?.versions

      const isPublished = !talentProfile?.localizationActive
        ? isCopyUrlPromptFeatureEnabled
          ? !!talentProfile?.currentVersionId
          : true
        : !newLocalizations.some(el => !el.isPublished) &&
          !versions?.length &&
          !currentIds?.length
      return isPublished
    },
    [talentProfile, localizationUnpublishIds]
  )

  //
  const onPublish = useCallback(
    async (localizationId = [null]) => {
      const profile = pickProfileInfo(talentProfile)
      let digitalProductsFilesToUpload

      if (isCopyUrlPromptFeatureEnabled) {
        copyTextToClipboard(profileLink(talentProfile?.user?.username))
      }

      if (isSaving) {
        // Cancel saving
        setIsSaving(false)
        debounceAutoSave.cancel()

        if (useFreeDownload && !!modules) {
          digitalProductsFilesToUpload =
            getDigitalProductsFilesToUpload(modules)
        }

        // Dispatch publish
        dispatch(
          forceSaveAndpublishProfileActions.REQUEST({
            localizationId: localizationSelected?.id,
            localizationIds: localizationId,
            profile,
            modules,
            ...(digitalProductsFilesToUpload && {
              digitalProductsFilesToUpload
            }),
            //manually pass user that aligns with auto save
            updatedById: collaborator?.id ?? user?.id,
            //manually pass talent id, that aligns with auto save
            updateTalentId: talentProfile?.id,
            onNetworkError: () =>
              onNetworkError(
                'Changes could not be published due to a network error.',
                // Callback for retry attempt on notification retry button click
                () => {
                  notification.destroy('auto-save-network-error')
                  onPublish(localizationId)
                }
              ),
            onSuccess: () => {
              dispatch(
                getLocalizationModulesActions.REQUEST({
                  localizationId: localizationSelected?.id,
                  talentProfileId: user?.talentProfile?.id,
                  loading: false
                })
              )
              const isPublished = getIsPublishedStatus(localizationId)
              updateAttributesData({ isPublished })

              if (isCopyUrlPromptFeatureEnabled) {
                createToast({
                  semantic: 'success',
                  text: 'Your Komi page has been successfully published and Komi link copied to your clipboard.',
                  dismissible: true,
                  durationMs: 5000
                })
              }
            }
          })
        )
      } else {
        dispatch(
          publishProfileActions.REQUEST({
            localizationId,
            publishTalentId: collaborator?.id ?? user?.id,
            onNetworkError: () =>
              onNetworkError(
                'Changes could not be published due to a network error.',
                () => {
                  notification.destroy('auto-save-network-error')
                  onPublish(localizationId)
                }
              ),
            onSuccess: () => {
              dispatch(
                getLocalizationModulesActions.REQUEST({
                  localizationId: localizationSelected?.id,
                  talentProfileId: user?.talentProfile?.id,
                  loading: false
                })
              )
              const isPublished = getIsPublishedStatus(localizationId)
              updateAttributesData({ isPublished })

              if (isCopyUrlPromptFeatureEnabled) {
                createToast({
                  semantic: 'success',
                  text: 'Your Komi page has been successfully published and Komi link copied to your clipboard.',
                  dismissible: true,
                  durationMs: 5000
                })
              }
            }
          })
        )
      }
      useAnalyticsSDK
        ? publishChanges()
        : sendSegmentEvent(SEGMENT_EVENTS.PUBLISH_CHANGES)
      setVisibleConfirmPublish(false)
    },
    [
      talentProfile,
      modules,
      isSaving,
      updateAttributesData,
      localizationSelected,
      user?.talentProfile?.id,
      getIsPublishedStatus,
      sendSegmentEvent,
      pickProfileInfo,
      isCopyUrlPromptFeatureEnabled
    ]
  )

  // Cancel the current save and
  const onForceSave = useCallback(
    (callback?: any) => {
      if (loadingAutoSave) {
        debounceAutoSave.cancel()

        onSaveProfile({
          newTalent: talentProfile,
          newModules: modules,
          localizationId: localizationSelected?.id,
          callback
        })
        return
      }
      callback?.()
    },
    [
      onSaveProfile,
      loadingAutoSave,
      localizationSelected,
      modules,
      talentProfile,
      debounceAutoSave
    ]
  )

  // Event handler for localization changes
  const handleChangeLocalization = useCallback(
    (locale: LocalizationItem) => {
      //If returning from add modules page, skip
      if (location.state?.retainModules) {
        //Clear the state so that it doesn't block future changes
        location.state.retainModules = false
        return
      }
      setIsChangePageLoading(true)

      // Callback to set localization
      const changeLocalization = () => {
        setLocalizationSelected(locale)
        dispatch(
          getLocalizationModulesActions.REQUEST({
            localizationId: locale?.id,
            talentProfileId: talentProfile?.id,
            loading: true
          })
        )
        dispatch(setActiveModuleAction(null))
        setIsChangePageLoading(false)
      }

      if (loadingAutoSave) {
        debounceAutoSave.cancel()
        onSaveProfile({
          newTalent: talentProfile,
          newModules: modules,
          localizationId: localizationSelected?.id,
          callback: changeLocalization
        })
      } else {
        changeLocalization()
      }
    },
    [
      dispatch,
      onSaveProfile,
      loadingAutoSave,
      talentProfile,
      modules,
      localizationSelected?.id,
      debounceAutoSave
    ]
  )

  const onCheckBeforeChangeRouter = useCallback(
    (location: any) => {
      if (isSaving && location.pathname === '/logout') {
        dispatch(
          forceSaveAndLogoutActions.REQUEST({
            localizationId: localizationSelected?.id,
            profile: talentProfile,
            modules: modules,
            onNetworkError: () =>
              onNetworkError(
                'Changes could not be saved due to a network error.',
                () => {
                  notification.destroy('auto-save-network-error')
                  onSaveProfile({
                    newModules: talentProfile,
                    newTalent: modules,
                    localizationId: localizationSelected?.id
                  })
                }
              )
          })
        )
        setIsSaving(false)
        return false
      }
      return true
    },
    [isSaving, talentProfile, modules, localizationSelected?.id]
  )
  const onDeleteLocalization = useCallback(
    (localizationId: string | null, page: any) => {
      const handleDelete = () => {
        dispatch(
          deleteLocalizationActions.REQUEST({
            localizationId,
            talentProfileId: user?.talentProfile?.id,
            onSuccess: () => {
              setLocalizationSelected(page)
              dispatch(
                getLocalizationModulesActions.REQUEST({
                  localizationId: page?.id,
                  talentProfileId: talentProfile?.id,
                  loading: true
                })
              )
              dispatch(setActiveModuleAction(null))
            }
          })
        )
      }
      if (loadingAutoSave) {
        debounceAutoSave.cancel()
        onSaveProfile({
          newTalent: talentProfile,
          newModules: modules,
          localizationId: localizationSelected?.id,
          callback: handleDelete
        })
        return
      }
      handleDelete()
    },
    [
      user,
      loadingAutoSave,
      onSaveProfile,
      modules,
      talentProfile,
      localizationSelected?.id
    ]
  )

  useEffect(() => {
    setLocalizationSelected(DEFAULT_PAGE)
  }, [])

  useEffect(() => {
    if (!localizationActive && localizationSelected?.id !== null) {
      handleChangeLocalization(DEFAULT_PAGE)
    }
  }, [localizationActive, localizationSelected?.id, handleChangeLocalization])

  useEffect(() => {
    const updateIds = () => {
      let newLocalizationIds: any[] = localizationUnpublishIds || []
      if (isModuleUpdated) {
        newLocalizationIds = [...newLocalizationIds, localizationSelected?.id]
      }
      if (isProfileUpdated) {
        newLocalizationIds = [...newLocalizationIds, null]
      }
      dispatch(setLocalizationUnpublishIdsAction(uniq(newLocalizationIds)))
    }
    if (
      moduleLoading ||
      isChangePageLoading ||
      !talentProfile ||
      !modules ||
      loadingDeleteLocalization
    ) {
      return
    }
    if (loadingAutoSave) {
      if (isModuleUpdated || isProfileUpdated) {
        debounceAutoSave.cancel()
        debounceAutoSave({
          newTalent: talentProfile,
          newModules: modules,
          localizationId: localizationSelected?.id
        })
      }
      return
    }

    if (isModuleUpdated || isProfileUpdated) {
      setIsSaving(true)
      isPublished && dispatch(setIsPublishedActions(false))
      dispatch(setLoadingAutoSaveActions(true))

      debounceAutoSave({
        newTalent: talentProfile,
        newModules: modules,
        localizationId: localizationSelected?.id
      })
      updateIds()
    }
  }, [
    isModuleUpdated,
    isProfileUpdated,
    talentProfile,
    modules,
    loadingAutoSave,
    moduleLoading,
    isChangePageLoading,
    loadingDeleteLocalization
  ])
  useEffect(() => {
    if (isBlockingEditState) {
      setBlocked(true)
    }
  }, [isBlockingEditState])

  useEffect(() => {
    if (!isBlockingEditState && blocked) {
      dispatch(getUserProfileActions.REQUEST())
    }
  }, [isBlockingEditState, blocked, dispatch])

  useEffect(() => {
    const currentUserId = collaborator?.id ?? user?.id

    if (router?.location?.pathname !== '/' || !currentUserId || !attributeKey) {
      return
    }
    if (isBlockingEdit) {
      debounceAutoSave.cancel()
      setIsBlockingEditState(true)
      return
    }
    let talentDataRef: firebase.database.Reference
    if (attributeKey && currentUserId) {
      talentDataRef = firebaseService.getDataRef(attributeKey)
      talentDataRef.on('value', snapshot => {
        const data = snapshot.val()
        const lastEdit = data?.lastEdit
        const lastConnection = lastEdit?.userId
          ? data[lastEdit.userId]?.lastConnection
          : null

        if (
          (data?.isPublished && isBlockingEditState) ||
          (lastEdit?.userId !== currentUserId &&
            isBlockingEditState &&
            lastConnection &&
            moment().valueOf() - moment(lastConnection).valueOf() >= 10000)
        ) {
          isBlockingEditState && setIsBlockingEditState(false)
          isSaving && setIsSaving(false)
        }

        if (
          !isBlockingEditState &&
          !data?.isPublished &&
          lastEdit?.updatedAt &&
          currentUserId &&
          lastEdit?.userId !== currentUserId &&
          lastConnection &&
          moment().valueOf() - moment(lastConnection).valueOf() < 10000 &&
          moment().valueOf() - moment(lastEdit?.updatedAt).valueOf() <
            MINUTES['15']
        ) {
          setIsBlockingEditState(true)
          debounceAutoSave.cancel()
        }
      })
    }
    return () => {
      if (talentDataRef) {
        talentDataRef.off()
      }
    }
  }, [
    talentProfile,
    attributeKey,
    collaborator?.id,
    user?.id,
    isCollaborator,
    isBlockingEditState,
    isBlockingEdit,
    isPublished,
    router?.location?.pathname
  ])

  const handleInteractEvent = useCallback(
    debounce(() => {
      localStorage.setItem(`EXPIRED_TIME`, `${Date.now() + MINUTES['15']}`)
    }, 1000),
    []
  )

  const handleLeavePage = (e: any) => {
    e.preventDefault()
    const confirmationMessage =
      'Some of the changes you’ve made have not been saved yet. Are you sure you want to leave?'
    e.returnValue = confirmationMessage
    return confirmationMessage
  }

  useEffect(() => {
    if (isSaving) {
      window.addEventListener('beforeunload', handleLeavePage)
      return () => window.removeEventListener('beforeunload', handleLeavePage)
    }
  }, [isSaving])

  useEffect(() => {
    document.addEventListener('keydown', handleInteractEvent)
    document.addEventListener('mousedown', handleInteractEvent)

    return () => {
      document.removeEventListener('keydown', handleInteractEvent)
      document.removeEventListener('mousedown', handleInteractEvent)
      window.removeEventListener('beforeunload', handleLeavePage)
    }
  }, [])

  async function onResendLink() {
    try {
      await authService.resendEmailConfirmation(
        user?.talentProfile?.user?.createdById!
      )
      notification.success({
        message: 'Your activation email has been resent'
      })
    } catch {
      notification.error({
        message: SOMETHING_WENT_WRONG
      })
    }
  }

  const closeModal = () => setVisibleConfirmPublish(false)

  return (
    <AutoSaveContext.Provider
      value={{
        localizationSelected,
        setLocalizationSelected,
        isVisiblePublish,
        setIsVisiblePublish,
        isChangePageLoading,
        setIsChangePageLoading,
        isSaving,
        setIsSaving,
        isBlockingEditState,
        setIsBlockingEditState,
        onCheckBeforeChangeRouter,
        onPublish,
        handleChangeLocalization,
        setVisibleConfirmPublish,
        onForceSave,
        onSaveProfile,
        onDeleteLocalization
      }}
    >
      {children}

      <IfFeature
        feature={FLAGS.FIX_PUBLISH_MODAL_LOGIC}
        enabled={
          <PrePublishModal
            show={visibleConfirmPublish}
            closeModal={closeModal}
            onPublish={onPublish}
          />
        }
        disabled={
          <>
            {user?.emailVerified || authService.emailVerified ? (
              isTemplatesV2Enabled && hasTemplateModules ? (
                <When
                  value={visibleConfirmPublish}
                  then={
                    <TemplatePublishWarningModal
                      onPublish={onPublish}
                      onClose={closeModal}
                    />
                  }
                />
              ) : (
                <ConfirmDeleteModal
                  show={visibleConfirmPublish}
                  reverse
                  title="You are About to Publish Your Updated Profile"
                  description="Once your updates are published, they will be reflected on the live version of your Komi page and everyone will be able to see them. Do you want to proceed?"
                  confirmLabel="PUBLISH"
                  cancelLabel="CANCEL"
                  handleConfirm={onPublish}
                  toggleModal={closeModal}
                />
              )
            ) : (
              <ConfirmDeleteModal
                show={visibleConfirmPublish}
                reverse
                title="Your email hasn't been confirmed"
                description="You will be able to publish once you have clicked on your activation link. Then, your updates will be reflected on the live version of your page."
                confirmLabel="CONTINUE"
                cancelLabel="RESEND LINK"
                handleConfirm={onPublish}
                handleCancel={onResendLink}
                toggleModal={closeModal}
              />
            )}
          </>
        }
      />
      <PublishModal
        visible={isVisiblePublish}
        setVisible={setIsVisiblePublish}
        onSubmit={onPublish}
      />
    </AutoSaveContext.Provider>
  )
}
