import React, { useState, useEffect } from 'react'
import { withClient, Client } from 'cozy-client'
import { FluidType } from 'enum/fluid.enum'
import { ScreenType } from 'enum/screen.enum'

import InitDataManager from 'services/initDataManagerService'
import UserProfileDataManager from 'services/userProfileDataManagerService'
import { UserChallenge, UserProfile } from 'services/dataChallengeContracts'

interface AppContextProps {
  isIndexesLoading: boolean
  isIndexesLoadingSuccess: boolean | null
  isDataLoading: boolean
  isDataLoadingSuccess: boolean | null
  isFluidTypesLoading: boolean
  isFluidTypesLoadingSuccess: boolean | null
  fluidTypes: FluidType[]
  refreshFluidTypes: Function
  isCurrentChallengeUpdateLoading: boolean
  isCurrentChallengeUpdateLoadingSuccess: boolean | null
  currentChallenge: UserChallenge | null
  challengeNotification: boolean
  refreshCurrentChallenge: Function
  isContextLoaded: boolean
  isError: boolean
  screenType: ScreenType
  userProfile: UserProfile | null
  setWelcomeModalViewed: Function
}

export const AppContext = React.createContext<AppContextProps>({
  isIndexesLoading: false,
  isIndexesLoadingSuccess: null,
  isDataLoading: false,
  isDataLoadingSuccess: null,
  isFluidTypesLoading: false,
  isFluidTypesLoadingSuccess: null,
  fluidTypes: [],
  refreshFluidTypes: () => null,
  isCurrentChallengeUpdateLoading: false,
  isCurrentChallengeUpdateLoadingSuccess: null,
  currentChallenge: null,
  challengeNotification: false,
  refreshCurrentChallenge: () => Promise,
  isContextLoaded: false,
  isError: false,
  screenType: ScreenType.MOBILE,
  userProfile: null,
  setWelcomeModalViewed: () => null,
})

interface AppContextProviderProps {
  children: React.ReactNode
  client: Client
}

const AppContextProvider: React.FC<AppContextProviderProps> = ({
  children,
  client,
}: AppContextProviderProps) => {
  const [isIndexesLoading, setIndexesLoading] = useState<boolean>(false)
  const [isIndexesLoadingSuccess, setIndexesLoadingSuccess] = useState<
    boolean | null
  >(null)

  const [isDataLoading, setDataLoading] = useState<boolean>(false)
  const [isDataLoadingSuccess, setDataLoadingSuccess] = useState<
    boolean | null
  >(null)

  const [isFluidTypesLoading, setFluidTypesLoading] = useState<boolean>(false)
  const [isFluidTypesLoadingSuccess, setFluidTypesLoadingSuccess] = useState<
    boolean | null
  >(null)

  const [fluidTypes, setFluidTypes] = useState<FluidType[]>([])

  const [
    isCurrentChallengeUpdateLoading,
    setCurrentChallengeUpdateLoading,
  ] = useState<boolean>(false)
  const [
    isCurrentChallengeUpdateLoadingSuccess,
    setCurrentChallengeUpdateLoadingSuccess,
  ] = useState<boolean | null>(null)
  const [
    currentChallenge,
    setCurrentChallenge,
  ] = useState<UserChallenge | null>(null)
  const [challengeNotification, setChallengeNotification] = useState<boolean>(
    false
  )

  const [isContextLoaded, setContextLoaded] = useState<boolean>(false)
  const [isError, setError] = useState<boolean>(false)
  const [screenType, setScreenType] = useState<ScreenType>(ScreenType.MOBILE)

  const [isUserProfileLoadingSuccess, setUserProfileLoadingSuccess] = useState<
    boolean | null
  >(null)
  const [userProfile, setUserProfile] = useState<UserProfile | null>(null)

  const defineScreenType = () => {
    if (screen.width <= 768) {
      setScreenType(ScreenType.MOBILE)
    } else if (screen.width <= 1024) {
      setScreenType(ScreenType.TABLET)
    } else {
      setScreenType(ScreenType.DESKTOP)
    }
  }

  const refreshFluidTypes = async () => {
    const im = new InitDataManager(client)
    const resultFluidTypes = await im.checkFluidTypes()
    if (resultFluidTypes) {
      setFluidTypes(resultFluidTypes)
      const resultAchievement = await im.checkAchievement('CHA00000001')
      if (resultAchievement) {
        const resultNotificationChallenge = await im.isCurrentChallengeOver(
          resultAchievement,
          resultFluidTypes
        )
        if (resultNotificationChallenge) {
          setChallengeNotification(resultNotificationChallenge)
        }
      }
    }
  }

  const setWelcomeModalViewed = async () => {
    const upm = new UserProfileDataManager(client)
    const updatedUserProfile = await upm.updateUserProfile({
      haveSeenWelcomeModal: true,
    })
    if (updatedUserProfile) {
      setUserProfile(updatedUserProfile)
    }
  }

  const refreshCurrentChallenge = async (): Promise<boolean> => {
    const im = new InitDataManager(client)
    try {
      const resultUpdateChallenge = await im.checkCurrentChallenge(fluidTypes)
      setCurrentChallenge(resultUpdateChallenge)
      if (resultUpdateChallenge) {
        const resultNotificationChallenge = await im.isCurrentChallengeOver(
          resultUpdateChallenge,
          fluidTypes
        )
        if (resultNotificationChallenge) {
          setChallengeNotification(resultNotificationChallenge)
        }
      } else {
        setChallengeNotification(false)
      }
      return true
    } catch {
      setCurrentChallenge(null)
      setChallengeNotification(false)
      return false
    }
  }

  useEffect(() => {
    let subscribed = true
    function handleResize() {
      defineScreenType()
    }
    handleResize()
    window.addEventListener('resize', handleResize)
    const im = new InitDataManager(client)
    const updm = new UserProfileDataManager(client)
    async function loadData() {
      // Create missing indexes
      setIndexesLoading(true)
      const resultIndexConsoData = await im.initIndex()
      if (subscribed && !resultIndexConsoData) {
        setIndexesLoadingSuccess(false)
        setError(true)
      }
      if (subscribed && resultIndexConsoData) {
        console.log(
          '%c Context: Indexes created',
          'background: #222; color: white'
        )
        setIndexesLoadingSuccess(true)
      }
      setIndexesLoading(false)

      // Load challenges, ecogestures and user profile data
      setDataLoading(true)
      const resultInitData = await im.initData()
      if (subscribed && !resultInitData) {
        setDataLoadingSuccess(false)
        setError(true)
      }
      if (subscribed && resultInitData) {
        setDataLoadingSuccess(true)
      }
      setDataLoading(false)

      // Load configured fluidTypes
      setFluidTypesLoading(true)
      const resultFluidTypes = await im.checkFluidTypes()
      if (subscribed && resultFluidTypes) {
        console.log(
          '%c Context: Konnectors loaded ',
          'background: #222; color: white'
        )
        setFluidTypes(resultFluidTypes)
        setFluidTypesLoadingSuccess(true)
      }
      setFluidTypesLoading(false)

      // Update current challenge if exists
      setCurrentChallengeUpdateLoading(true)
      try {
        const resultUpdateChallenge = await im.checkCurrentChallenge(
          resultFluidTypes ? resultFluidTypes : []
        )
        if (subscribed && resultUpdateChallenge) {
          const resultNotificationChallenge = await im.isCurrentChallengeOver(
            resultUpdateChallenge,
            resultFluidTypes ? resultFluidTypes : []
          )
          if (subscribed && resultNotificationChallenge) {
            setChallengeNotification(resultNotificationChallenge)
          }
        }
        if (subscribed) {
          console.log(
            '%c Context: Current Challenge checked',
            'background: #222; color: white'
          )
          setCurrentChallenge(resultUpdateChallenge)
          setCurrentChallengeUpdateLoadingSuccess(true)
        }
      } catch {
        setCurrentChallengeUpdateLoadingSuccess(false)
        setError(true)
      } finally {
        setCurrentChallengeUpdateLoading(false)
      }

      //Retrieve the UserProfile
      const loadedUserProfile = await updm.getUserProfile()
      if (!loadedUserProfile) {
        setError(true)
      }
      if (subscribed && loadedUserProfile) {
        console.log(
          '%c Context: UserProfile Loaded',
          'background: #222; color: white'
        )
        setUserProfile(loadedUserProfile)
        setUserProfileLoadingSuccess(true)
      }
    }
    loadData()
    return () => {
      subscribed = false
      window.removeEventListener('resize', handleResize)
    }
  }, [])

  useEffect(() => {
    if (
      isIndexesLoadingSuccess &&
      isDataLoadingSuccess &&
      isFluidTypesLoadingSuccess &&
      isCurrentChallengeUpdateLoadingSuccess &&
      isUserProfileLoadingSuccess &&
      !isError
    ) {
      setTimeout(function() {
        setContextLoaded(true)
      }, 1000)
    }
  }, [
    isIndexesLoadingSuccess,
    isDataLoadingSuccess,
    isFluidTypesLoadingSuccess,
    isCurrentChallengeUpdateLoadingSuccess,
    isUserProfileLoadingSuccess,
    isError,
  ])

  return (
    <AppContext.Provider
      value={{
        isIndexesLoading,
        isIndexesLoadingSuccess,
        isDataLoading,
        isDataLoadingSuccess,
        isFluidTypesLoading,
        isFluidTypesLoadingSuccess,
        fluidTypes,
        refreshFluidTypes,
        isCurrentChallengeUpdateLoading,
        isCurrentChallengeUpdateLoadingSuccess,
        currentChallenge,
        challengeNotification,
        refreshCurrentChallenge,
        isContextLoaded,
        isError,
        screenType,
        userProfile,
        setWelcomeModalViewed,
      }}
    >
      {children}
    </AppContext.Provider>
  )
}

export default withClient(AppContextProvider)