import {
  isServer,
  dashToCamel,
  globalVar,
  createContext,
  getNextConfig, getHeader, queryOrCookieStrToObj, getBaseUrlComponents, replaceCultureCodeInURL
} from '$ustoreinternal/services/utils'
import themeContext from '$ustoreinternal/services/themeContext'
import { UStoreProvider, http } 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 { Router } from '$routes'
import { CookiesManager, storefrontCookies } from '$ustoreinternal/services/cookies'

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 redirectToLogout = (ctx) => {
  const { securityToken, storeFriendlyID, storeID, languageCode, logoutUrl } = themeContext.get()
  const storeType = UStoreProvider && UStoreProvider.state.get().currentStore && UStoreProvider.state.get().currentStore.StoreType
  CookiesManager.deleteCookie(storefrontCookies.token)

  if (storeType === 3 && logoutUrl)
    redirectToFullURL(ctx, decodeURIComponent(logoutUrl))
  else
    redirectToLegacy(ctx, `logout.aspx?SecurityToken=${securityToken}&StoreGuid=${storeID}&storeid=${storeFriendlyID}ShowRibbon=false&forceLogin=true&NgLanguageCode=${languageCode}`)
}

export const redirectToStoreErrorPage = (ctx) => {
  redirectToLegacy(ctx, 'ShowMessage.aspx?ErrorCode=0')
}

export const redirectToGenericErrorPage = (ctx) => {
  redirectToLegacy(ctx, `errorPage.aspx`)
}

export const redirectToLegacy = (ctx, legacyURL) => {
  const { classicUrl } = themeContext.get()
  const url = `${classicUrl}/${legacyURL}`
  if (ctx && ctx.res) {
    ctx.res.writeHead(302, {
      Location: url
    })
    ctx.res.end()
  } else {
    window.location.href = url
  }
  return {}
}

const redirectToFullURL = (ctx, newURL) => {
  if (ctx && ctx.res) {
    ctx.res.writeHead(302, {
      Location: newURL
    })
    ctx.res.end()
  } else {
    window.location.href = newURL
  }
  return {}
}

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) {
    ['securityToken', 'storeBaseURL', 'storeID', 'FriendlyID'].forEach(key => themeContext.deleteKey(key))

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

    let loginResponse = await http.post(`${publicRuntimeConfig.apiUrl}/v1/store/loginByUrl`, { FullURL: url, UserID: currentUser }, { auth: false })

    if ((!loginResponse.Token || !loginResponse.Token.Token) && !loginResponse.URL) {
      // in case no new token returned, or API failed, redirect to logout.
      redirectToGenericErrorPage(ctx)
      return false
    }

    // save info from API to context and cookie
    themeContext.set('storeBaseURL', undefined)
    themeContext.set('securityToken', loginResponse.Token.Token)
    themeContext.set('storeID', loginResponse.StoreID)
    themeContext.set('userID', loginResponse.UserID)

    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()) {

      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: loginResponse.UserID, days: USER_ID_EXPIRATION_DAYS })
    }

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

    let returnURL = loginResponse.URL

    if (returnURL) {
      returnURL += returnURL.includes('?') ? '&ShowRibbon=true' : '?ShowRibbon=true'
      // check if return URL is logout page, and if so, append the ShowRibbon=true
      if (returnURL.toLowerCase().includes('logout.aspx')) {
        returnURL += '&forceLogin=true'
      }

      redirectToFullURL(ctx, returnURL)
      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 }
}
