<template lang="pug">
main.view--onboarding
    article(
        style='display: flex; flex-direction: column; align-items: center'
        v-if='currentStep !== survey.steps.length'
    )
        .answers(v-for='(value, key) in answered')
            span(v-if='key == "name" && value && currentStep == 2') Hi {{ value }}!
        br
        .step(v-for='(step, i) in survey.steps')
            component(
                :is='step.component'
                :question='step'
                :answered='answered'
                :responses='responses'
                :survey='survey'
                :currentStep='currentStep'
                :surveyStepsCount='survey.steps.length'
                @handle-submit='onSubmit'
                @update-answers='updateAnswers'
                v-if='step && currentStep == i'
            ) 
        .invalidResponseMessage(
            style='text-align: center'
            v-if='invalidResponse'
        )
            p {{ survey.steps[currentStep].invalidInputPrompt }}

        footer
            p(v-if='currentStep != 0') You have completed: {{ currentStep }} / {{ survey.steps.length }} survey steps

    article(v-else)
        SurveyCompleteView(:answers='answered' :surveySteps='survey.steps')
</template>

<script>
import { Authenticator } from '../services/auth.service.js'
import { fetchUserByEmail } from '../services/user.service.js'
import {
    fetchProfilesByUserId,
    fetchProfileByProfileId,
} from '../services/profile.service.js'
import { surveyFactory } from '@/utils'
import stepViews from '@/components/onboarding'
import SurveyCompleteView from './SurveyCompleteView.vue'
let sessionToken = null
let accessToken = null
let currentProfileId = null

export default {
    name: 'OnboardingView',
    components: {
        ...stepViews,
        SurveyCompleteView,
    },
    data: () => ({
        answered: {},
        aspectQuestions: [],
        responses: [],
        currentStep: 0,
        survey: null,
        invalidResponse: false,
        authenticator: {},
    }),
    async created() {
        this.survey = await surveyFactory.createSurvey()
        this.authenticator = new Authenticator()
        // TODO: Note that all this try/catch can be in a function instead,
        // since it has to be done on created() and every step after 6...
        sessionToken = this.grabStoredCookie('siimee_session')
        accessToken = this.grabStoredCookie('siimee_access')
        // TODO: More graceful way of throwing exceptions if sessionData is not defined??
        try {
            const sessionData = await this.verifyBothTokens()
            await this.isEmailInRegistry(sessionData.payload.email)
            // TODO: Validate All routes hit by these methods using tokens in headers
            const userId = await this.grabUserIdByEmail(
                sessionData.payload.email,
            )
            currentProfileId = await this.grabProfileIdByUserId(userId)
            this.responses = await this.grabResponsesByProfileId(
                currentProfileId,
            )
            this.currentStep = this.responses.length + 3
            this.goToStep(this.currentStep)
        } catch (err) {
            console.error('ERROR :=>', err)
            this.goToStep(0)
        }
    },
    methods: {
        onSubmit() {
            console.log(JSON.stringify(this.answered))
        },
        async goToStep(num) {
            this.currentStep = num
        },
        grabStoredCookie(cookieKey) {
            const cookies = document.cookie
                .split('; ')
                .reduce((prev, current) => {
                    const [name, ...value] = current.split('=')
                    prev[name] = value.join('=')
                    return prev
                }, {})
            const cookieVal =
                cookieKey in cookies ? cookies[`${cookieKey}`] : undefined
            return cookieVal
        },
        async verifyBothTokens() {
            const sessionTokenIsValid = await this.verifySessionToken(
                sessionToken,
            )
            const accessTokenIsValid = await this.verifyAccessToken(accessToken)
            if (
                accessTokenIsValid.status === 401 &&
                sessionTokenIsValid.status !== 401
            ) {
                console.warn(
                    'WARNING :=> Access Token Expired, but Session Token Is Still Valid, reissuing Access Token...',
                )
                // TODO: break out reissuing new tokens into separate _function
                const newAccessToken = await this.authenticator.getAccessToken(
                    sessionTokenIsValid.payload,
                )
                const newAccessTokenIsValid = await this.verifyAccessToken(
                    newAccessToken,
                )
                accessToken = newAccessToken
                document.cookie = `siimee_access=${newAccessToken}; max-age=600; path=/; secure`
                // NOTE: Resetting Session Token otherwise session
                // token will always expire after 10 minutes...???
                const newSessionToken =
                    await this.authenticator.getSessionToken(
                        sessionTokenIsValid.payload,
                    )
                sessionToken = newSessionToken
                document.cookie = `siimee_session=${newSessionToken}; max-age=600; path=/; secure`
                return newAccessTokenIsValid
            } else if (
                accessTokenIsValid.status === 401 &&
                sessionTokenIsValid.status === 401
            ) {
                sessionToken = null
                accessToken = null
                currentProfileId = null
                throw new Error('Both Session and Access Token Are Expired!!')
            } else return accessTokenIsValid
        },
        async verifySessionToken(sessionToken) {
            if (!sessionToken) {
                return console.warn('WARNING :=> sessionToken is not defined')
            } else return await this.validateToken(sessionToken)
        },
        async verifyAccessToken(accessToken) {
            if (!accessToken) {
                return console.warn('WARNING :=> accessToken is not defined')
            } else return await this.validateToken(accessToken)
        },
        async validateToken(token) {
            const validatedToken = await this.authenticator.validateSession(
                token,
            )
            if (validatedToken.error) {
                throw new Error(validatedToken.error)
            } else {
                return validatedToken
            }
        },
        async isEmailInRegistry(email) {
            const emailIsInRegistry =
                await this.authenticator.checkIfEmailIsRegistered(email)
            if (!emailIsInRegistry) {
                throw new Error('Email Is NOT in Registry!')
            } else return emailIsInRegistry
        },
        async grabUserIdByEmail(email) {
            const user = await fetchUserByEmail(email)
            if (!user) {
                throw new Error('User NOT found by email')
            } else return user.user_id
        },
        async grabProfileIdByUserId(userId) {
            const profilesFromUserId = await fetchProfilesByUserId(userId)
            if (
                profilesFromUserId.length === 1 &&
                profilesFromUserId.status !== 401
            ) {
                return profilesFromUserId[0].profile_id
            } else if (profilesFromUserId.length > 1) {
                // TODO: Refactor once more is known on users with multiple profiles
                throw new Error('Multiple Profiles for this User ID')
            } else {
                throw new Error('No Profile for User ID found')
            }
        },
        async grabProfileByProfileId(profileId) {
            const profile = await fetchProfileByProfileId(profileId)
            if (!profile || profile.status === 401) {
                throw new Error(`No Profile Found for profileId ${profileId}`)
            } else {
                return profile
            }
        },
        async grabResponsesByProfileId(profileId) {
            const responses = []
            const profile = await this.grabProfileByProfileId(profileId)
            if (!profile.responses.length || profile.responses.status === 401) {
                throw new Error(`No Responses Found for profileId ${profileId}`)
            } else {
                profile.responses.forEach(response => {
                    responses.push({
                        response_key_id: response.response_key_id,
                        val: response.val,
                    })
                })
                return responses
            }
        },
        async updateAnswers(payload) {
            if (payload) {
                const k = payload.question.survey_stage
                this.answered[k] = payload.input
                // Once validated, don't log password in answered object
                this.answered[k] = k === 'password' ? undefined : payload.input
                // Hacky WorkAround for Validating Answers
                if (!this.survey.validateAnswer(payload)) {
                    this.invalidResponse = true
                    return
                }
                // Formats initial responses for response table
                const response = {}
                response.response_key_id = payload.question.response_key_id
                response.val = payload.input
                this.responses.push(response)
                if (k === 'aspects') return
            }
            if (currentProfileId) {
                // TODO: Still have to authenticate this route
                await surveyFactory.addNewSurveyAnswer(
                    this.responses[this.responses.length - 1],
                    currentProfileId,
                    accessToken,
                )
                try {
                    await this.verifyBothTokens(sessionToken, accessToken)
                } catch (err) {
                    this.currentStep = 0
                    this.goToStep(this.currentStep)
                    throw new Error(err)
                }
            }
            if (this.currentStep > this.survey.steps.length) {
                this.onSubmit(this.answered)
            } else {
                this.goToStep(this.currentStep + 1)
            }
        },
    },
}
</script>

<style lang="sass">
.view--onboarding
    width: 100%
    max-width: 428px
    background-color: #fff
    color: #1F2024
    font-family: Century Gothic,CenturyGothic,AppleGothic,sans-serif
    margin: 0 auto

    article
        height: 100vh

    .answers
        text-align: center

    .w-button
            display: flex
            width: 315px
            height: 60px
            border-radius: 6
            background-color: #D5D5D5
            color: #1F2024
            margin: 11px auto
            font-weight: bold
            font-size: 16px
            text-transform: uppercase
            &.next-btn
                border-radius: 6px
                background-color: #5BA626
                color: #1F2024
                height: 50px
                width: 315px
                font-size: 18px
                padding: 7px

    .w-card
        background-color: #1F2024
        justify-content: center
        align-items: center
        width: 100%


        h3
            text-transform: uppercase
            text-align: center
            font-size: 28px
            font-weight: bold
            color: white
            margin-top: 88px

        p
            color: white
            font-size: 18px
            padding: 11px
            text-align: center
            margin: 22px auto
            font-weight: bold

        input
            display: flex
            width: 315px
            height: 60px
            padding: 11px
            border-radius: 6
            background-color: #D5D5D5
            color: #1F2024
            margin: 11px auto
            font-weight: bold
            font-size: 16px

            .w-select
                padding: 11px
                color: #1F2024

            .search-type
                color: #1F2024
                height: 50px

        &.question
            p
                font-size: 18px
                text-align: left
                margin: 7px auto
                font-weight: normal
            section
                p
                    margin: 0
                    font-weight: bold
                    text-transform: capitalize
    .w-radio__input

        &.primary
            background-color: #FFFFFF
            border: #BCC5D3 1px solid

    .w-card__content
        .w-button
            height: 50px
            background-color: #5BA626
</style>
