import {
  isServer,
  dashToCamel,
  globalVar,
  createContext,
  getNextConfig, getHeader, queryOrCookieStrToObj, getBaseUrlComponents, replaceCultureCodeInURL
} from '$ustoreinternal/services/utils'
import themeContext from '$ustoreinternal/services/themeContext'
import { UStoreProvider } from '@ustore/core'
import pages from '$themepages/index'
import i18n from 'roddeh-i18n'
import { loadLocalization } from '$ustoreinternal/services/localization'
import { initiateThemeState } from '$themeservices/initThemeState'
import { CookiesManager, storefrontCookies } from '$ustoreinternal/services/cookies'
import {
  returnToUrl,
  setCookies,
  saveInfoFromApi,
  redirectToFullURL,
  redirectToStoreErrorPage,
  redirectToGenericErrorPage,
  redirectToLogout,
  loginByUrlCall
} from './redirect'

export const USER_ID_EXPIRATION_DAYS = 30

const getUserInitialProps = async (initialPropsFunctionName, ctx) => {
  const routedPage = Object.keys(pages).filter(p => p.toLowerCase() === initialPropsFunctionName.toLowerCase())

  if (routedPage.length > 0 && pages[routedPage].getInitialProps) {
    return await pages[routedPage].getInitialProps(ctx)
  }

  return pages.Home.getInitialProps ? await pages.Home.getInitialProps(ctx) : {}
}

export const getInitialProps = (ctx) => {
  const { buildType } = getNextConfig()
  if (isServer() && buildType === 'client_only') {
    return {}
  }
  return initialLoad(ctx)
}

export const initAndLogin = async (ctx, url) => {
  const publicRuntimeConfig = getNextConfig()

  const res = getBaseUrlComponents(url)

  if (!res) return

  const { storeBaseURL: storeBaseFromURL, cultureCode: cultureCodeFromURL } = res
  const storedCultureCode = isServer() ? getHeader(ctx.req, storefrontCookies.language) : CookiesManager.getCookie(storefrontCookies.language)
  if (storedCultureCode && storedCultureCode !== cultureCodeFromURL) {
    redirectToFullURL(ctx, replaceCultureCodeInURL(url, storedCultureCode))
    return false
  }

  const storeBaseFromMem = themeContext.get('storeBaseURL') || CookiesManager.getCookie(storefrontCookies.storeBaseURL) || (ctx && getHeader(ctx.req, storefrontCookies.storeBaseURL))

  let securityTokenFromUrl = ''
  let shouldCookieRibbonBeShown = CookiesManager.getCookie(storefrontCookies.cookieRibbonNotShownYet) || ' true'
  if (ctx) {
    if (ctx.query && ctx.query.SecurityToken) securityTokenFromUrl = ctx.query.SecurityToken
    if (ctx.query && ctx.query.ShowRibbon) shouldCookieRibbonBeShown = ctx.query.ShowRibbon.toLowerCase()

  } else if (!isServer()) {
    const searchStr = window.location.search.substring(1)

    if (searchStr) {
      const q = queryOrCookieStrToObj(searchStr)

      if (q.SecurityToken) {
        securityTokenFromUrl = q.SecurityToken
      }
      if (q.ShowRibbon) {
        shouldCookieRibbonBeShown = q.ShowRibbon.toLowerCase()
      }
    }
  }
  const shouldCallLoginByUrl = !!url && !securityTokenFromUrl &&
    (themeContext.get('securityToken') === undefined || !themeContext.get('securityToken') ||
      (storeBaseFromMem && storeBaseFromURL !== storeBaseFromMem))
  const date = new Date()
  date.setTime(date.getTime() + (USER_ID_EXPIRATION_DAYS * 24 * 60 * 60 * 1000))
  const expires = '; expires=' + date.toUTCString()

  if (shouldCallLoginByUrl) {
    const loginResponse = await loginByUrlCall(publicRuntimeConfig, url, ctx)
    if (loginResponse) {

      saveInfoFromApi(loginResponse)

      if (ctx && ctx.res && ctx.res.getHeader && ctx.res.setHeader) {
        const cookiesFromReq = queryOrCookieStrToObj(ctx.req.headers.cookie)
        if (cookiesFromReq[storefrontCookies.cookieRibbonNotShownYet]) {
          shouldCookieRibbonBeShown = cookiesFromReq[storefrontCookies.cookieRibbonNotShownYet]
        }

        const cookiesToPush = ctx.res.getHeader('Set-Cookie') || []
        cookiesToPush.push(`${storefrontCookies.token}=${loginResponse.Token.Token}; path=/`)
        cookiesToPush.push(`${storefrontCookies.storeID}=${loginResponse.StoreID}; path=/`)
        cookiesToPush.push(`${storefrontCookies.storeBaseURL}=${storeBaseFromURL}; path=/`)
        // need to save the user ID to the cookie, so that if he closes the browser and reopens he wont lose his data.
        cookiesToPush.push(`${storefrontCookies.userID}=${loginResponse.UserID}; path=/${expires}`)
        cookiesToPush.push(`${storefrontCookies.cookieRibbonNotShownYet}=${shouldCookieRibbonBeShown}; path=/`)
        ctx.res.setHeader('Set-Cookie', cookiesToPush)
      } else if (!isServer()) {
        setCookies(storeBaseFromURL, shouldCookieRibbonBeShown, loginResponse)
      }

      // raise the showRibbon flag, so if not redirecting to logout, NG will show the cookie ribbon.
      UStoreProvider.state.customState.set('showCookieRibbon', JSON.parse(shouldCookieRibbonBeShown))

      return returnToUrl(loginResponse, ctx)
    }
    return false
  } else {
    if (ctx && ctx.res && ctx.res.getHeader && ctx.res.setHeader) {
      const cookiesFromReq = queryOrCookieStrToObj(ctx.req.headers.cookie)
      if (cookiesFromReq[storefrontCookies.cookieRibbonNotShownYet]) {
        shouldCookieRibbonBeShown = cookiesFromReq[storefrontCookies.cookieRibbonNotShownYet]
      }

      const cookiesToPush = []
      cookiesToPush.push(`${storefrontCookies.token}=${themeContext.get('securityToken')}; path=/`)
      cookiesToPush.push(`${storefrontCookies.storeID}=${themeContext.get('storeID')}; path=/`)
      cookiesToPush.push(`${storefrontCookies.storeBaseURL}=${storeBaseFromURL}; path=/`)
      // need to save the user ID to the cookie, so that if he closes the browser and reopens he wont lose his data.
      cookiesToPush.push(`${storefrontCookies.userID}=${themeContext.get('userID')}; path=/${expires}`)
      cookiesToPush.push(`${storefrontCookies.cookieRibbonNotShownYet}=${shouldCookieRibbonBeShown}; path=/`)
      ctx.res.setHeader('Set-Cookie', cookiesToPush)
    } else if (!isServer()) {
      CookiesManager.setCookie({ key: storefrontCookies.token, value: themeContext.get('securityToken') })
      CookiesManager.setCookie({ key: storefrontCookies.storeID, value: themeContext.get('storeID') })
      CookiesManager.setCookie({ key: storefrontCookies.storeBaseURL, value: storeBaseFromURL })
      CookiesManager.setCookie({ key: storefrontCookies.cookieRibbonNotShownYet, value: shouldCookieRibbonBeShown })
      // need to save the user ID to the cookie, so that if he closes the browser and reopens he wont lose his data.
      CookiesManager.setCookie({
        key: storefrontCookies.userID,
        value: themeContext.get('userID'),
        days: USER_ID_EXPIRATION_DAYS
      })
    }

    UStoreProvider.state.customState.set('showCookieRibbon', JSON.parse(shouldCookieRibbonBeShown))
  }

  themeContext.set('storeBaseURL', storeBaseFromURL)
  await UStoreProvider.init(publicRuntimeConfig, {
    ...themeContext.get(),
    onAccessDenied: () => redirectToLogout(ctx),
    onStoreNotAvailable: () => redirectToStoreErrorPage(ctx),
    onGeneralError: () => redirectToGenericErrorPage(ctx),
  }).then(() => {
    initiateThemeState()
  })

  return true

}

export const initialLoad = async (ctxParam) => {

  const ctx = ctxParam || createContext()
  if (isServer()) {
    themeContext.init(ctx)
  } else {
    themeContext.updateRouteParams(ctx)
  }

  let fullUrl
  // in dev mode wait for load localizations
  if (isServer()) {
    fullUrl = ctx.req.protocol + '://' + ctx.req.get('host') + themeContext.context['assetPrefix'] + ctx.asPath.substring(1)
    const keys = await loadLocalization(themeContext.get(), themeContext.context['languageCode'], fullUrl)
    globalVar.uStoreLocalization = {
      [themeContext.context['languageCode']]: i18n.create({ values: keys }),
      storeFriendlyID: ctx.query.storeFriendlyID
    }

  } else {
    fullUrl = window ? window.location.href : ''
  }

  let shouldContinue = await initAndLogin(ctx, fullUrl)

  // if should not continue, do not load further data.
  if (!shouldContinue) return {}
  // }

  const { page } = themeContext.get()
  const initialPropsFunctionName = dashToCamel(page)

  //sets the user initial props to custom state.
  const userInitialProps = await getUserInitialProps(initialPropsFunctionName, ctx)
  if (userInitialProps) {
    UStoreProvider.state.customState.setBulk(userInitialProps)
  }

  const userCustomState = { customState: { ...UStoreProvider.state.get().customState, ...userInitialProps } }

  // returns the state from the component to be rendered.
  return { state: { ...UStoreProvider.state.get(), ...userCustomState }, context: ctx.query }
}
